A1
A_ID (PK)
A_ID
A2
A_ID (PK)
C_ID
A3
C_ID (PK)
C_Code
C_Name
というテーブルがあったとする。
判っているのは A1_ID で、このA1_IDからA2テーブルをたどって、A3テーブルの情報をとりたい、とする。
このときに使いたいSQLには色々とあるとおもうのだけれど以下の二つがある、とする。
SQL-Server2005で実行する場合、早いのはどっち~?
(1)
SELECT A3.C_ID, A3.C_Code,
A3.C_Name
FROM A3
INNER JOIN A1 ON
A1.A_ID=150
INNER JOIN A2 ON
A2.A_ID = A1.A_ID AND
A2.C_ID = A3.C_ID
ORDER BY A3.C_ID
(2)
SELECT A3.C_ID, A3.C_Code,
A3.C_Name
FROM A3 WHERE C_ID =
(SELECT C_ID FROM A2 WHERE A_ID =
(SELECT A2 FROM A1 WHERE A_ID = 150))
ORDER BY A3.C_ID
答え、検索元テーブルレコード数、抽出対象レコード数が少ないと実はあんまり変わんない(死)
けれどデータ量が増えたとき、早いのは(1)みたい(^^;
実は、実際にSQLの実行プランを表示してみると両者の違いがはっきりと出るのです。諸事情によりプラン図出せないので、文章になりますけれど……
(1)の場合
A2とA3クラスターインデックスで検索→NestedLoops→結果とA1のクラスターインデックス結果でNestedLoops→結果
(2)の場合
A2とA3クラスターインデックスで検索→NestedLoops→結果をStreamAggregate→Assert→
結果とA1のクラスターインデックス結果でNestedLoops→結果
消費コストはどちらも同じで、最後のNestedLoopsで3%、残りを3つのクラスターインデックス検索で分けています。つまり、SELECT文を使用した場合には、インデックスで検索した後で「これ、いる?いらない?」の判断処理が入っていてレコードの取捨選択があり、その分処理のステップが増えているんですね。INNER JOIN命令っていうのは「取捨選択?そんなの関係ねぇ!」ばりにくっつくデータをを無条件に持ってくる、と。」
データ量が少ない時にはそんなに意識しなくっても良いし、それこそ標準化と可読性に重きを置いておいても良いのかもしれない。でも、データ量が増える可能性があるときに備え、データ量が多いテーブルでのデータ処理、テーブルキー関係と正規化を把握して、できるだけ処理コストとステップを抑えたSQLが書けるようにしておくと良いかも、ですです。