😯

駆動表、内部表ってどっちでもいいの?

2023/01/26に公開

先に結論

どっちでもよくない

駆動表とは

駆動表とは、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回)
アクセスの回数が減りましたね。

わかりやすいようにちょっと無理に例えてみましたが、実際の結合時も上のようなことが起きています。
駆動表は最初にアクセス/フェッチされるテーブルです。
駆動表の桁数が少ない方が、アクセス/フェッチする回数が減って楽でいいよねって話です。

まとめ

駆動表、内部表ってどっちでもよくないです。

参照

https://kazootkr.hatenablog.com/entry/2021/02/27/195135
https://zenn.dev/nakunaru/articles/cf663e62fc1a7b

Discussion