オプティマイザはアクセス・プラン用に左側が深い処理ツリーを生成します。このルールの唯一の例外は、右側が深いネスト外部ジョイン式の存在です。LEFT OUTER JOIN または RIGHT OUTER JOIN の計算に使用するクエリ実行エンジンのアルゴリズムでは、どのようなジョイン方式の場合も、保護されたテーブルを NULL 入力テーブルよりも前に置きます。そのため、オプティマイザはできるだけ LEFT または RIGHT 外部ジョインを内部ジョインに変換しようとします。これは、内部ジョインは交換可能で、オプティマイザがジョイン列挙を実行するときの自由度が大きくなるためです。
次のいずれかの条件を満たす場合に、LEFT または RIGHT 外部ジョインが内部ジョインに変換されます。
このリライト最適化を外部ジョイン・クエリに適用できるのは、クエリが外部結合を使用して作成された 1 つ以上のビューを参照する場合です。クエリの WHERE 句には、1 つ以上のテーブル式からの NULL 入力ローをすべて削除するように出力を制限する条件を含めることができるため、この最適化が適用可能になります。
次のクエリの場合、ProductID カラムは NOT NULL と宣言されており、SalesOrderItems テーブルは外部キー "FK_ProductID_ID" ("ProductID") REFERENCING "Products" ("ID")
を持つため、SalesOrderItems テーブルの各ローには Products テーブルと一致するローが 1 つだけ存在します。
次の SELECT 文は、リライト最適化後の書き換えられたクエリを示しています。
SELECT * FROM SalesOrderItems s LEFT OUTER JOIN Products p ON (p.ID = s.ProductID); SELECT * FROM SalesOrderItems s JOIN Products p ON (p.ID = s.ProductID); |
次のクエリは、数量の多い製品とそれに対応する注文をリストします。LEFT OUTER JOIN は、注文がなくても全製品をリストするためのものです。
SELECT * FROM Products p KEY LEFT OUTER JOIN SalesOrderItems s WHERE s.Quantity > 15; |
このクエリの問題は、s.Quantity
が NULL の場合に WHERE 句の述部 s.Quantity > 15
が FALSE として解釈されるため、注文のない製品がこの述部によって結果から削除されることです。このクエリは、セマンティック上は次に示すものと同じです。
SELECT * FROM Products p KEY JOIN SalesOrderItems s WHERE s.Quantity > 15; |
データベース・サーバが最適化するのも、クエリを書き換えたこの形式になります。
この例で、クエリが正しく書き換えられないのはほぼ確実です。正しくは、次のようにする必要があります。
SELECT * FROM Products p KEY LEFT OUTER JOIN SalesOrderItems s ON s.Quantity > 15; |
この場合、Quantity のテストは外部ジョイン条件の一部になっています。2 つのクエリの相違を示すために、順序のない Products テーブルに新しい製品を挿入してから、クエリを再実行してみます。
INSERT INTO Products SELECT ID + 10, Name, Description, 'Extra large', Color, 50, UnitPrice, Photo FROM Products WHERE Name = 'Tee Shirt'; |
Copyright © 2009, iAnywhere Solutions, Inc. - SQL Anywhere 11.0.1 |