こんにちは!データベースの世界へようこそ。
普段、何気なくSQLを書いて「データを取ってくる」という作業をしていると、裏側でデータベースがどんなふうに頑張っているのか、なかなか想像しづらいですよね。
今日は、PostgreSQLがテーブル同士をくっつけるときに使う、一番シンプルで、でも奥が深い「ネステッドループ結合」についてお話しします。
専門用語を並べるのは一旦お休みして、ちょっとした日常の場面に例えてみましょう。
—
2つのリストを照らし合わせる作業
想像してみてください。あなたは今、「クラス名簿(テーブルA)」と、その生徒たちの「テストの点数表(テーブルB)」を突き合わせて、全員分の成績表を作ろうとしています。
さて、あなたならどんな手順で作業しますか?
きっと、こんなふうにやるはずです。
1. 名簿の一番上の生徒の名前を見る。
2. 点数表のリストを上から順に目で追って、その生徒の点数を探す。
3. 見つけたら成績表に書き込む。
4. 次に、名簿の2番目の生徒の名前を見る。
5. また点数表を上から順に見て、点数を探す……。
これを最後の人まで繰り返しますよね。
この「外側のリスト(名簿)を1行ずつめくりながら、そのたびに内側のリスト(点数表)を最初から最後までチェックする」というやり方。これがまさに、データベース界の「ネステッドループ結合(Nested Loop Join)」なんです。
—
なぜ「ネステッド」と呼ぶの?
「ネステッド(Nested)」とは「入れ子」という意味です。
プログラミングの世界でいう「ループの中にループがある」状態、つまり「二重ループ」のことですね。
先ほどの例で言うと……
- 外側のループ:名簿を1人ずつ進める
- 内側のループ:点数表を1件ずつ探す
この2つが重なっているので、ネステッドループと呼ばれます。シンプルでしょう?
—
このアルゴリズムの「得意」と「苦手」
このやり方は、とても直感的でわかりやすいですよね。でも、どんな仕事にも向き不向きがあるように、ネステッドループにも得意なシーンと、ちょっと厳しいシーンがあるんです。
得意なとき:小規模なとき
名簿が5人分しかなければ、この方法は最強に早いです。準備もいらないし、すぐに取り掛かれますからね。データベースでも、データ量が少ないときや、検索条件で「たった1人(または数人)」を特定できているときは、この方法が一番効率的です。
苦手なとき:大規模なとき
もし、名簿が1万人分あって、点数表も100万件あったらどうでしょう?
「1万人全員に対して、そのたびに100万行のリストを最初から最後まで探す」……。考えただけで気が遠くなりますよね。
もし名簿の生徒全員分をこのやり方でやろうとしたら、データベースは途方もない回数の「探し物」をすることになり、結果が出るまでにものすごく時間がかかってしまいます。
—
データベースの「賢い工夫」
実際のPostgreSQLは、この単純なネステッドループをもう少しだけ賢く使います。
もし、点数表のほうに「インデックス(索引)」がついていたらどうなるでしょうか?
点数表の最初から最後まで指でなぞる必要はなく、辞書を引くように「その生徒の点数」をパッと一瞬で見つけ出せますよね。
PostgreSQLは、インデックスが使える状態であれば、「ネステッドループ結合」を驚くほど高速にこなすことができるんです。
—
まとめ:今日のポイント
- ネステッドループ結合は「二重ループ」:外側のテーブルを1行ずつ見ながら、内側のテーブルを都度確認するやり方。
- 基本はシンプル:データ量が少ないときや、特定の行をピンポイントで探すときには最高のパフォーマンスを発揮します。
- インデックスが命:データ量が多くなっても、内側のテーブルにインデックスがあれば、この手法はまだまだ現役で活躍できます。
「結合」と聞くと難しく感じますが、実は私たちが普段やっている「照らし合わせ作業」と何も変わりません。
「あ、今のクエリはネステッドループで動いてるんだな。ということは、内側のテーブルにインデックスを貼ったらもっと速くなるかも?」
そんなふうに、データベースの気持ちになって考えてみると、チューニングがぐっと楽しくなりますよ。ぜひ、皆さんの環境でも `EXPLAIN` コマンドを使って、PostgreSQLがどんなふうに結合しているのか覗いてみてくださいね!
それでは、また次回のブログでお会いしましょう。ハッピー・コーディング!
コメント