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

AnalyticDB:主キーおよび外部キー制約を活用した冗長な JOIN の削除

最終更新日:Mar 28, 2026

テーブルが結合されているにもかかわらず、クエリがそのうち 1 つのテーブルからのみ列を読み取る場合、AnalyticDB for MySQL はその結合が冗長であることを証明し、実行計画から削除できます。これにより、SQL を変更することなくレイテンシを低減できます。この機能を「結合削除」と呼び、宣言された主キー (PK) および外部キー (FK) 制約の関係に依存します。

重要

AnalyticDB for MySQL の FK および PK 制約は情報提供専用であり、システムはデータ整合性を強制しません。すべての FK 値が有効な PK 値を参照していることを、ユーザー自身で保証する必要があります。宣言された制約に反するデータが存在する場合、結合削除後にクエリが誤った結果を返す可能性があります。

前提条件

開始する前に、以下の条件を満たしていることを確認してください。

  • AnalyticDB for MySQL クラスターがバージョン 3.1.10 以降で実行中であること

Data Lakehouse Edition クラスターのマイナーバージョンを確認するには、SELECT adb_version(); を実行します。マイナーバージョンをアップグレードするには、テクニカルサポートまでお問い合わせください。

結合削除の仕組み

オプティマイザーは、FK-PK 制約情報を使用して、結合が結果セットを変更するかどうかを判断します。クエリがテーブル A(FK 側)とテーブル B(PK 側)を宣言済みの FK-PK 列ペアで結合し、かつクエリがテーブル B の列を選択しない場合、以下の条件が成立します。

  • テーブル A の各行は、テーブル B の各行と最大 1 件のみマッチします(B の列が PK であるため)。

  • 結合はテーブル A の行をフィルター処理したり、複製したりしません。

  • したがって、この結合は冗長であり、単独でテーブル A をスキャンした場合と結果は同一です。

これらの条件が満たされる場合、オプティマイザーは結合を、FK テーブルに対する単一の TableScan に置き換えます。

クエリ単位でこの動作を有効化または無効化するには、/*+ PK_FK_DEPENDENCY_ENABLED*/ ヒントを使用します。

ヒント効果
/*+ PK_FK_DEPENDENCY_ENABLED = true*/FK-PK に基づく結合削除を有効化
/*+ PK_FK_DEPENDENCY_ENABLED = false*/FK-PK に基づく結合削除を無効化

外部キーの宣言

テーブル作成時(CREATE TABLE)に外部キーを宣言するか、後から追加または削除します(ALTER TABLE)。CREATE TABLE の構文詳細については、「CREATE TABLE」をご参照ください。また、ALTER TABLE の構文詳細については、「ALTER TABLE」をご参照ください。

制限事項

制限事項詳細
単一列外部キーのみ外部キーは 1 列のみを参照できます。FOREIGN KEY (sr_item_sk, sr_ticket_number) REFERENCES store_sales(ss_item_sk, d_date_sk) のような複数列外部キーはサポートされていません。
データ制約の検証なしAnalyticDB for MySQL は FK-PK 間のデータ整合性を検証しません。結合削除を利用する前に、データが宣言された制約を満たしていることを確認してください。
外部テーブル外部テーブルには外部キー制約を追加できません。
DROP TABLE 動作DROP TABLE 文で外部キーを削除する場合、AnalyticDB for MySQL はこの操作を検証せず、エラーも報告しません。
1 回の ALTER TABLE 文で 1 つの外部キーのみALTER TABLE で複数の外部キーを追加する場合は、各外部キーごとに個別の文を実行してください。

CREATE TABLE による外部キーの宣言

同一データベース内の外部キー

  1. データベースおよびプライマリテーブルを作成します。

    CREATE DATABASE db;
    USE db;
    CREATE TABLE item
    (
      i_item_sk bigint NOT NULL,
      i_current_price bigint,
      PRIMARY KEY(i_item_sk)
    )
    DISTRIBUTED BY HASH(i_item_sk);
  2. 外部キーとして item を参照するテーブルを作成します。

    symbol を指定しない場合、パーサーは自動的に制約名を <column_name>_fk とします。本例では、制約名は sr_item_sk_fk となります。
    CREATE TABLE store_returns
    (
      sr_sale_id bigint,
      sr_store_sk bigint,
      sr_item_sk bigint NOT NULL,
      FOREIGN KEY (sr_item_sk) REFERENCES item (i_item_sk)
    );

クロスデータベース外部キー

他のデータベース内のテーブルを参照するには、テーブル名の前にデータベース名を付与します。

CREATE DATABASE db2;
USE db2;
CREATE TABLE store_sales
(
  ss_sale_id bigint,
  ss_store_sk bigint,
  ss_item_sk bigint not null,
  CONSTRAINT fk_constraint FOREIGN KEY (ss_item_sk) REFERENCES db.item (i_item_sk)
);

単一テーブルへの複数外部キーの宣言

1 つの CREATE TABLE 文に複数の FOREIGN KEY 句を含めます。

  1. 参照先テーブルを作成します。

    USE db;
    CREATE TABLE customer
    (
      i_customer_sk bigint NOT NULL,
      i_current_price bigint,
      PRIMARY KEY(i_customer_sk)
    )
    DISTRIBUTED BY HASH(i_customer_sk);
    
    CREATE TABLE vendor
    (
      id bigint primary key,
      name varchar(5) not null
    );
  2. 2 つの外部キーを持つテーブルを作成します。

    CREATE TABLE store_product
    (
      sr_sale_id bigint,
      sr_store_sk bigint,
      sr_customer_sk bigint NOT NULL,
      FOREIGN KEY (sr_sale_id) REFERENCES vendor (id),
      FOREIGN KEY (sr_customer_sk) REFERENCES customer (i_customer_sk)
    );

ALTER TABLE による外部キーの宣言

既存のテーブルに対して外部キーを追加または削除するには、ALTER TABLE を使用します。1 回の文で 1 つの外部キーのみを処理します。複数の外部キーを管理する場合は、複数回の文を実行してください。

外部キーの追加:

USE db;
ALTER TABLE store_returns ADD CONSTRAINT sr_item_fk FOREIGN KEY (sr_item_sk) REFERENCES item (i_item_sk);

外部キーの削除:

USE db;
ALTER TABLE store_returns DROP FOREIGN KEY sr_item_sk_fk;

他のデータベースを参照する外部キーの追加:

-- ステップ 1:db2 に参照先テーブルを作成
USE db2;
CREATE TABLE store
(
  id bigint primary key,
  name varchar(5) not null
);

-- ステップ 2:db.store_returns から db2.store への外部キーを追加
ALTER TABLE db.store_returns ADD FOREIGN KEY (sr_store_sk) REFERENCES store(id);

宣言済み外部キーの確認

テーブル上の外部キー定義を確認するには、SHOW CREATE TABLE を使用します。

USE db;
SHOW CREATE TABLE store_returns;

サンプル出力(その他の文は省略):

-- CONSTRAINT `sr_item_sk_fk` FOREIGN KEY (`sr_item_sk`) REFERENCES `db`.`item`(`i_item_sk`)

結合削除の適用

外部キーが宣言された後、クエリに /*+ PK_FK_DEPENDENCY_ENABLED = true*/ ヒントを追加します。オプティマイザーは、以下の条件を満たす結合を削除します。

  • 結合条件が宣言済みの FK-PK 関係と一致すること

  • クエリが結合された PK テーブルの列を選択しないこと

生成された実行計画には、FK テーブルに対する TableScan のみが含まれ、InnerJoin オペレーターは表示されません。

同一データベース内の 2 つのテーブル

store_returns.sr_item_skitem.i_item_sk を参照する外部キーを持ちます。クエリは store_returns のみの列を選択しています。i_item_sk は PK であるため、各 sr_item_sk 値は item の行と最大 1 件のみマッチし、結合によって結果セットが変更されることはありません。そのため、オプティマイザーはこの結合を削除します。

/*+ PK_FK_DEPENDENCY_ENABLED = true*/
EXPLAIN
SELECT
  s.sr_sale_id,
  s.sr_store_sk,
  s.sr_item_sk
FROM
  store_returns s,
  item
WHERE
  sr_item_sk = i_item_sk;

実行計画には TableScan のみが表示され、InnerJoin オペレーターは存在しません。

+---------------+
| 実行計画の概要 |
+---------------+
 1- Output[ Query plan ] {Est rowCount: 1.0}
 2    -> Exchange[GATHER] {Est rowCount: 1.0}
 3        - TableScan {table: store_returns, Est rowCount: 1.0}

クロスデータベースの 2 つのテーブル

クロスデータベースの外部キー関係にも同様のロジックが適用されます。db2.store_sales.ss_item_skdb.item.i_item_sk を参照します。クエリは store_sales のみの列を選択しているため、db.item との結合は冗長です。

USE db2;
/*+ PK_FK_DEPENDENCY_ENABLED = true*/
EXPLAIN
SELECT
  s.ss_sale_id,
  s.ss_item_sk
FROM
  store_sales s,
  db.item
WHERE
  ss_item_sk = i_item_sk;

サンプル出力:

+---------------+
| 実行計画の概要 |
+---------------+
 1- Output[ Query plan ] {Est rowCount: 1.0}
 2    -> Exchange[GATHER] {Est rowCount: 1.0}
 3        - TableScan {table: store_sales, Est rowCount: 1.0}

複数テーブルの結合

クエリ内のすべての結合が冗長である場合、オプティマイザーはそれらを 1 回のパスで削除します。本例では、store_returnsitem および db2.store の両方を参照する外部キーを持ち、クエリは store_returns のみの列を読み取ります。

USE db;
/*+ PK_FK_DEPENDENCY_ENABLED = true*/
EXPLAIN
SELECT
  s.sr_sale_id,
  s.sr_store_sk,
  s.sr_item_sk
FROM
  store_returns s,
  item,
  db2.store
WHERE
  sr_item_sk = i_item_sk
  AND sr_store_sk = id;

サンプル出力:

+---------------+
| 実行計画の概要 |
+---------------+
 1- Output[ Query plan ] {Est rowCount: 1.0}
 2    -> Exchange[GATHER] {Est rowCount: 1.0}
 3        - TableScan {table: store_returns, Est rowCount: 1.0}

ビュー内の結合

複数のテーブルを基に定義されたビューに対しても、結合削除は機能します。store_returns および item を結合するビューを作成します。

CREATE VIEW sr_item_v AS
SELECT
  s.sr_store_sk AS store_name,
  s.sr_sale_id AS sale_id,
  s.sr_item_sk AS sr_item_id,
  item.i_current_price AS item_price,
  item.i_item_sk as item_id
FROM
  store_returns s,
  item
WHERE
  sr_item_sk = i_item_sk;

ビューに対するクエリで、item_price(または item のみから取得可能な他の任意の列)を参照しない場合、結合削除がトリガーされます。オプティマイザーは item.i_item_sk への参照を store_returns.sr_item_sk に置き換え、store_returns のみをスキャンします。

/*+ PK_FK_DEPENDENCY_ENABLED = true*/
EXPLAIN
SELECT store_name, sr_item_id, sale_id
FROM sr_item_v;

サンプル出力:

+---------------+
| 実行計画の概要 |
+---------------+
 1- Output[ Query plan ] {Est rowCount: 1.0}
 2    -> Exchange[GATHER] {Est rowCount: 1.0}
 3        - TableScan {table: store_returns, Est rowCount: 1.0}

結合削除が適用されない場合:item のみから解決可能な列(例:item_price)をクエリが選択する場合、結合は必須であり、オプティマイザーはこれを保持します。

/*+ PK_FK_DEPENDENCY_ENABLED = true*/
EXPLAIN
SELECT store_name, sr_item_id, sale_id, item_price
FROM sr_item_v;

サンプル出力 — 実行計画に InnerJoin[Hash Join] が表示されます。

+---------------+
| 実行計画の概要 |
+---------------+
 1- Output[ Query plan ] {Est rowCount: 1.0}
 2    -> Exchange[GATHER] {Est rowCount: 1.0}
 3        -> InnerJoin[Hash Join] {Est rowCount: 1.0}
 4            -> Project {Est rowCount: 1.0}
 5                -> Exchange[REPARTITION] {Est rowCount: 1.0}
 6                    - TableScan {table: store_returns, Est rowCount: 1.0}
 7            -> LocalExchange[HASH] {Est rowCount: 1.0}
 8                -> ScanProject {table: item, Est rowCount: 1.0}
 9                    - TableScan {table: item, Est rowCount: 1.0}