すべてのプロダクト
Search
ドキュメントセンター

PolarDB:JOIN 除去

最終更新日:Dec 04, 2025

複数テーブルに対する JOIN 操作は、複雑な分析クエリにおいて一般的なパフォーマンスボトルネックです。PolarDB for MySQL の JOIN 除去機能は、クエリ最適化フェーズで不要な JOIN 操作を特定して削除します。これにより、実行計画が簡素化され、I/O と計算が削減され、クエリのパフォーマンスが向上します。

利用シーン

  • 製品エディション:Cluster Edition および Standard Edition

  • MySQL バージョン:MySQL 8.0.2、リビジョン 8.0.2.2.31.1 以降。

JOIN 除去の有効化

パラメーター join_elimination_mode を設定することで、この最適化機能の動作を制御できます。

PolarDB クラスターのパラメーターの変更方法は、コンソールとデータベースセッションで異なります。違いは次のとおりです:

  • PolarDB コンソール の場合

    • 互換性:MySQL の設定ファイルとの互換性を確保するため、PolarDB コンソールの一部のクラスターパラメーターには loose_ プレフィックスが付いています。

    • 手順loose_ プレフィックスが付いたパラメーターを検索して変更します。

  • データベースセッション (コマンドラインまたはクライアントを使用) の場合

    • 手順SET コマンドを使用してデータベースセッションでパラメーターを変更する場合、loose_ プレフィックスを削除し、元のパラメーター名を使用します。

パラメーター

レベル

説明

loose_join_elimination_mode

グローバル/セッション

この機能のメインスイッチを制御します。有効な値は次のとおりです:

  • REPLICA_ON (デフォルト):読み取り専用 (RO) ノードでのみこの機能を有効にします。

  • ON:この機能を有効にします。

  • OFF:この機能を無効にします。

最適化シナリオ

この機能は、次の 6 つのシナリオで JOIN の自動除去をサポートします。

シナリオ 1:定数 FALSE 条件を持つ LEFT JOIN の除去

LEFT JOINON 条件が常に FALSE の場合、その結合は意味をなしません。オプティマイザーは内部テーブルを削除し、そのすべての列を NULL に置き換えます。

-- 最適化前
SELECT ..., ti1.*, ti2.*, ... FROM ... LEFT JOIN (ti1, ti2, ...) ON FALSE;
-- 最適化後
SELECT ..., NULL, NULL, ... FROM ...;

除去の条件

LEFT JOINON 条件が、1=0FALSE のように、常に FALSE となる式であること。

  1. 環境の準備

    DROP TABLE IF EXISTS orders;
    CREATE TABLE orders (
        order_id INT PRIMARY KEY,
        customer_id INT,
        order_date DATE
    );
    DROP TABLE IF EXISTS customers;
    CREATE TABLE customers (
        customer_id INT PRIMARY KEY,
        customer_name VARCHAR(100)
    );
    INSERT INTO orders VALUES (1, 101, '2023-10-01');
  2. 最適化前:JOIN 除去を無効にし、ON FALSE を使用してクエリを実行します。

    SET SESSION join_elimination_mode = 'OFF';
    EXPLAIN SELECT o.*, c.* FROM orders o LEFT JOIN customers c ON FALSE;
    SHOW warnings;
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Level | Code | Message                                                                                                                                                                                                                                                                                                                          |
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Note  | 1003 | /* select#1 */ select `testdb`.`o`.`order_id` AS `order_id`,`testdb`.`o`.`customer_id` AS `customer_id`,`testdb`.`o`.`order_date` AS `order_date`,`testdb`.`c`.`customer_id` AS `customer_id`,`testdb`.`c`.`customer_name` AS `customer_name` from `testdb`.`orders` `o` left join `testdb`.`customers` `c` on(false) where true |
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  3. 最適化後:JOIN 除去を有効にし、同じクエリを実行します。

    SET SESSION join_elimination_mode = 'ON';
    EXPLAIN SELECT o.*, c.* FROM orders o LEFT JOIN customers c ON FALSE;
    SHOW warnings;
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Level | Code | Message                                                                                                                                                                                                                    |
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Note  | 1003 | /* select#1 */ select `testdb`.`o`.`order_id` AS `order_id`,`testdb`.`o`.`customer_id` AS `customer_id`,`testdb`.`o`.`order_date` AS `order_date`,NULL AS `customer_id`,NULL AS `customer_name` from `testdb`.`orders` `o` |
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

    実行計画から、customers テーブルへのアクセスが除去されたことがわかります。

シナリオ 2:結果に影響を与えない一意キーでの LEFT JOIN の除去

LEFT JOIN の内部テーブルがクエリの他の部分で参照されておらず、かつ JOIN 操作が外部テーブルの行数を変更しない場合、内部テーブルの JOIN は安全に除去できます。

-- 最適化前
SELECT to1.*, to2.*, ..., tom.* FROM to1, to2, ..., tom LEFT JOIN (ti1, ti2, ..., tin) ON cond_on WHERE cond_where ...
-- 最適化後
SELECT to1.*, to2.*, ..., tom.* FROM to1, to2, ..., tom WHERE cond_where ...

除去の条件

  • 内部テーブルが参照されていない:内部テーブル (つまり ti1, ti2, ..., tin) の列が、LEFT JOIN とその ON 条件の外で参照されていないこと。

  • JOIN が外部テーブルのカーディナリティや結果に影響を与えない:次のいずれかの条件を満たす必要があります。

    • 結合が一意である:外部テーブルの各行に対して、LEFT JOIN が内部テーブルのちょうど 1 行に一致する。

    • JOIN によって生成される重複行が結果に影響を与えない:JOIN によって外部テーブルの行が重複しても、クエリ内の後続の操作がこれらの重複の影響を排除する。一般的なケースは次のとおりです:

      • JOIN が EXISTS または IN 句 (SEMI JOIN) の中にある。

      • サブクエリに GROUP BYLIMIT、またはウィンドウ関数などの条件が含まれている。

      • 上記の 2 つの条件の再帰的な使用。

シナリオ 3:自己結合の除去

ベーステーブル (またはその派生テーブル) が INNER JOIN を使用して自身と結合される場合、これは 2 つの同一または類似のデータセットを照合することに相当します。特定の条件が満たされると、オプティマイザーはデータセットの 1 つを冗長とみなし、同じデータを 2 回読み取ることを避けるために実行計画から除去できます。

  • ベーステーブルとベーステーブルの結合:

    -- 最適化前
    SELECT target.*, source.* FROM t1 as target JOIN t1 as source WHERE target.uk = source.uk;
    -- 最適化後
    SELECT source.*, source.* FROM source WHERE source.uk = source.uk;
  • 派生テーブルと派生テーブルの結合:

    -- 最適化前
    SELECT target.*, source.* FROM (SELECT * FROM t1) target JOIN (SELECT * FROM t1 WHERE t1.a > 1) source WHERE target.uk = source.uk;
    -- 最適化後
    SELECT source.*, source.* FROM (SELECT * FROM t1 WHERE t1.a > 1) source WHERE source.uk = source.uk;
  • ベーステーブルと派生テーブルの結合:

    -- 最適化前
    SELECT target.*, source.* FROM t1 target JOIN (SELECT * FROM t1 WHERE t1.a > 1) source WHERE target.uk = source.uk;
    -- 最適化後
    SELECT source.*, source.* FROM (SELECT * FROM t1 WHERE t1.a > 1) source WHERE source.uk = source.uk;

除去の条件

  • サブセット関係source テーブルの結果セットは、target テーブルの結果セットのサブセットでなければなりません。

  • 列の可用性target テーブルから参照されるすべての列は、source テーブルにも存在しなければなりません。これにより、保持される source テーブルがクエリに必要なすべての列を含むことが保証されます。

  • 一意キー結合JOIN 条件は、target テーブルの一意キーまたはプライマリキーに基づく等価比較でなければなりません。

    • この条件は、source テーブルの各行が target テーブルの最大 1 行に一致することを保証するため非常に重要です。これにより、target テーブルを除去しても行数やクエリ結果が変わらないことが保証されます。

    • 特殊なケース:結合条件に一意キーに基づく等価比較がない場合、除去は target テーブル自体の結果セットに 0 行または 1 行しか含まれていない場合にのみ可能です。

シナリオ 4:自己セルフジョインの除去

テーブルが自身とセルフジョインされる場合 (SEMI JOIN、通常は IN または EXISTS 句として表現される)、特定の条件が満たされれば、サブクエリ内のテーブルを除去し、その条件を外部クエリにマージできます。

  • 一意の列の等価条件がある場合。

    -- 最適化前
    SELECT source.* FROM t1 as source WHERE EXISTS (SELECT * FROM t1 as target WHERE source.uk = target.uk AND target.a > 1);
    -- 最適化後
    SELECT source.* FROM t1 as source WHERE source.uk = source.uk AND source.a > 1;
  • 一意の列の等価条件がない場合。

    -- 最適化前
    SELECT source.* FROM t1 as source WHERE EXISTS (SELECT * FROM t1 as target WHERE source.a = target.a);
    -- 最適化後
    SELECT source.* FROM t1 as source WHERE source.a = source.a;

除去の条件

  • サブセット関係source テーブルの結果セットは、target テーブルの結果セットのサブセットでなければなりません。

  • 列の可用性target テーブルから参照されるすべての列は、source テーブルにも存在しなければなりません。これにより、保持される source テーブルがクエリに必要なすべての列を含むことが保証されます。

  • さらに、次のいずれかの条件を満たす必要があります:

    • 一意キー結合JOIN 条件は、target テーブルの一意キーまたはプライマリキーに基づく等価比較でなければなりません。

      • この条件は、source テーブルの各行が target テーブルの最大 1 行に一致することを保証するため非常に重要です。これにより、target テーブルを除去しても行数やクエリ結果が変わらないことが保証されます。

      • 特殊なケース:結合条件に一意キーに基づく等価比較がない場合、除去は target テーブル自体の結果セットに 0 行または 1 行しか含まれていない場合にのみ可能です。

    • すべての結合条件が等価結合 (つまり、) であり、AND によって他の条件と接続されている。

シナリオ 5:外部キー結合の除去

2 つのテーブル間に外部キー制約が存在する場合、JOIN 条件がこの外部キー関係に基づいており、クエリが子テーブル (外部キーを持つテーブル) の列のみを参照している場合、親テーブルの結合は除去できます。これは、外部キー制約によって、子テーブルのすべての行が親テーブルに対応する行を持つことが保証されるためです。

CREATE TABLE target (a int primary key);
CREATE TABLE source (a int, foreign key (a) references target(a));

-- 最適化前
SELECT target.a, source.a FROM target, source WHERE target.a = source.a;
-- 最適化後
SELECT source.a, source.a FROM source WHERE source.a = source.a;

除去の条件

  • 親テーブルの参照が置換可能である:親テーブルから参照されるすべての列が、子テーブルの対応する外部キー列で置換可能であること。これは通常、親テーブルの結合キーのみが参照されることを意味します。

  • 結合条件が外部キー関係に基づいているJOIN 条件が、子テーブルの外部キー列と親テーブルのプライマリキーまたは一意キー列との間の等価比較であること。

  • 外部キーが null でない:子テーブルの外部キー列が NOT NULL として定義されていること。これにより、子テーブルのすべての行が親テーブルに対応する行を持つことが保証されます。

シナリオ 6:外部キーセルフジョインの除去

EXISTS または IN 句を使用して、外部キー関係に基づいて親テーブルに対応するレコードが存在するかどうかを確認する場合、このチェックは冗長です。外部キー制約によって、レコードが存在することはすでに保証されています。したがって、SEMI JOIN サブクエリは除去できます。

CREATE TABLE target (a int primary key);
CREATE TABLE source (a int, foreign key (a) references target(a));

-- 最適化前
SELECT source.a FROM source WHERE EXISTS(SELECT * FROM target WHERE target.a = source.a);
-- 最適化後
SELECT source.a FROM source WHERE source.a = source.a;

除去の条件

  • 親テーブルの参照が置換可能である:親テーブルから参照されるすべての列が、子テーブルの対応する外部キー列で置換可能であること。これは通常、親テーブルの結合キーのみが参照されることを意味します。

  • 結合条件が外部キー関係に基づいているJOIN 条件が、子テーブルの外部キー列と親テーブルのプライマリキーまたは一意キー列との間の等価比較であること。

  • 外部キーが null でない:子テーブルの外部キー列が NOT NULL として定義されていること。これにより、子テーブルのすべての行が親テーブルに対応する行を持つことが保証されます。

よくある質問

join_elimination_mod を有効にしてもクエリが最適化されないのはなぜですか?

次の手順で問題をトラブルシューティングしてください:

  1. バージョンの確認:「利用シーン」で指定されている要件をクラスターバージョンが満たしていることを確認してください。

  2. シナリオの確認:SQL 文とテーブルスキーマが、このドキュメントで説明されている 6 つの最適化シナリオのいずれかの除去条件を満たしていることを確認してください。

  3. SELECT リストの確認:LEFT JOINFOREIGN KEY JOIN などのシナリオでは、クエリの SELECT リストが、除去対象のテーブルの列を一切参照していないことを確認してください。

  4. クエリの複雑性の確認:特定のネストされたサブクエリなど、一部の複雑なクエリ構造では、オプティマイザーが除去を実行できない場合があります。テストのためにクエリを簡素化してみてください。

この機能はデータ整合性やクエリ結果の正確性に影響しますか?

いいえ、影響はありません。JOIN 除去は、クエリ結果が同等であることが保証されている場合にのみ実行される論理的な最適化です。クエリの実行方法のみを変更し、そのセマンティクスやクエリ結果は変更しません。すべての最適化は、正しい結果を保証するために厳密な条件チェックに基づいています。