高度に正規化されたスキーマやビューに基づくクエリレイヤーでは、多くの LEFT JOIN 句を含む SQL が生成されることが多く、その大部分は論理的に冗長です。つまり、結合されるテーブルが結果セットに一切寄与していません。LEFT JOIN 除去は、オプティマイザーのレベルでこうした冗長な結合を削除する機能であり、データベースは実際に必要なテーブルのみを読み込みます。複雑な分析クエリにおいては、SQL を一切変更せずに実行時間を 10 倍以上短縮できます。
仕組み
クエリ内の各 LEFT JOIN について、PolarDB for MySQL は以下の 2 つの条件を検証します。
左側テーブルの各行に対して、右テーブルの行は結合条件を満たすものが 1 行のみ存在すること。
右テーブルの列が、
SELECTリストまたはクエリ内の他の任意の場所で参照されていないこと。
両条件を満たす場合、PolarDB は実行計画から当該結合を削除します。オプティマイザーはクエリ内のすべての LEFT JOIN に対してこの検証を適用するため、複数の冗長な結合を同時に除去できます。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
PolarDB for MySQL 8.0 クラスター(リビジョンバージョン 8.0.1.1.32 以降、または 8.0.2.2.10 以降)
制限事項
LEFT JOIN 除去は、以下の **両方** の条件が満たされた場合にのみ適用されます。
左側テーブルの各行に対して、右テーブルの行は結合条件を満たすものが 1 行のみ存在すること。
右テーブルの列が、
LEFT JOIN句自体以外の SQL ステートメント内のいかなる場所でも参照されていないこと。
LEFT JOIN 除去の有効化
loose_join_elimination_mode パラメーターを設定することで、本機能の有効化タイミングを制御できます。
| パラメーター | レベル | 説明 |
|---|---|---|
loose_join_elimination_mode | グローバル | LEFT JOIN 除去を制御します。デフォルト値: REPLICA_ON。有効な値: ON(全ノードで有効)、REPLICA_ON(読み取り専用ノードのみで有効)、OFF(無効)。 |
パラメーターの変更については、「クラスターおよびノードのパラメーターの指定」をご参照ください。
デフォルト値 REPLICA_ON では、読み取り専用ノードでのみ本機能が有効になります。プライマリノードを含む全ノードで有効にするには、パラメーターを ON に設定してください。
EXPLAIN による検証
EXPLAIN を使用して、LEFT JOIN 除去がクエリに適用されているかを確認できます。
最適化前
以下のクエリでは、table1(エイリアス:sc)、table2(エイリアス:ca)、table3(エイリアス:co)が結合されています。各 table1 の行は、table2 および table3 の行とそれぞれ 1 対 1 でマッチし、table2 および table3 の列は SELECT リストに一切出現しません。したがって、両方の除去条件を満たしています。
EXPLAIN
SELECT count(*)
FROM `table1` `sc`
LEFT JOIN `table2` `ca` ON `sc`.`car_id` = `ca`.`id`
LEFT JOIN `table3` `co` ON `sc`.`company_id` = `co`.`id`;出力:
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+
| 1 | SIMPLE | sc | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL |
| 1 | SIMPLE | ca | NULL | eq_ref | PRIMARY | PRIMARY | 4 | je_test.sc.car_id | 1 | 100.00 | Using index |
| 1 | SIMPLE | co | NULL | eq_ref | PRIMARY | PRIMARY | 4 | je_test.sc.company_id | 1 | 100.00 | Using index |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+実行計画には 3 つのテーブルがすべて表示されます。実行時間:7.5 秒。
最適化後
LEFT JOIN 除去が有効化されている場合、オプティマイザーは table2 および table3 への結合が冗長であると検出し、クエリを書き換えて table1 のみをスキャンするようにします。
EXPLAIN
SELECT count(*)
FROM `table1` `sc`出力:
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| 1 | SIMPLE | sc | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+実行計画には table1 のみが残ります。実行時間:0.1 秒 — 元のクエリと比較して 75 倍高速です。