駆動表、内部表ってどっちでもいいの?
先に結論
どっちでもよくない
駆動表とは
駆動表とは、JOINにおいて最初にアクセスされるテーブル。
(後からアクセスされるテーブルが内部表です)
駆動表はどうやって決まるのよ
決してFROM句で指定したテーブルが駆動表になるとは限りません。
(最初はそんな風に思っていました..
下記の例の場合テーブルAが絶対、駆動表とは限らないわけです。
SELECT *
FROM テーブルA
INNER JOIN テーブルB
on テーブルA.id = テーブルB.hoge_id;
駆動表は行数が少ないほうが効率が良いので、そういったことをオプティマイザが考えてくれて決定します。
どちらが駆動表になっても変わらない?
そんなことは決してありません。
前述した様に、駆動表は行数が少ないほうが効率が良いです。
「いやでも、ネステッド・ループ結合(NLJ)って、以下のようにfor文で掛け算のようなものだから、どっちが駆動表でも変わらなくないですか?!」って思いますよね...。
for each レコード in テーブルA {
for each レコード in テーブルB {
send 結合したレコード to client
}
}
駆動表は行数が少ない方が好まれる理由
テーブルAとテーブルBの、結合の簡単な例を見てみましょう。(indexなどは全く貼られていない設定です)
駆動表は、JOINにおいて最初にアクセスされるテーブルです、
下の例の場合テーブルAが駆動表となります。
テーブルA,レコード1にアクセス
→ テーブルB,レコード1にアクセスして結合条件確認
→ テーブルB,レコード2にアクセスして結合条件確認
テーブルA,レコード2にアクセス
→ テーブルB,レコード1にアクセスして結合条件確認
→ テーブルB,レコード2にアクセスして結合条件確認
テーブルA,レコード3にアクセス
→ テーブルB,レコード1にアクセスして結合条件確認
→ テーブルB,レコード2にアクセスして結合条件確認
テーブルA,レコード4にアクセス
→ テーブルB,レコード1にアクセスして結合条件確認
→ テーブルB,レコード2にアクセスして結合条件確認
さて合計で何回アクセスしたでしょう。
12回ですね。(テーブルA 4回、テーブルB 8回)
次は駆動表をテーブルBにしてみます
テーブルB,レコード1にアクセス
→ テーブルA,レコード1にアクセスして結合条件確認
→ テーブルA,レコード2にアクセスして結合条件確認
→ テーブルA,レコード3にアクセスして結合条件確認
→ テーブルA,レコード4にアクセスして結合条件確認
テーブルB,レコード2にアクセス
→ テーブルA,レコード1にアクセスして結合条件確認
→ テーブルA,レコード2にアクセスして結合条件確認
→ テーブルA,レコード3にアクセスして結合条件確認
→ テーブルA,レコード4にアクセスして結合条件確認
さて合計で何回アクセスしたでしょう。
10回です...!!!!(テーブルA 8回、テーブルB 2回)
アクセスの回数が減りましたね。
わかりやすいようにちょっと無理に例えてみましたが、実際の結合時も上のようなことが起きています。
駆動表は最初にアクセス/フェッチされるテーブルです。
駆動表の桁数が少ない方が、アクセス/フェッチする回数が減って楽でいいよねって話です。
まとめ
駆動表、内部表ってどっちでもよくないです。
参照
Discussion