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

PolarDB:冗長な DISTINCT 操作の排除

最終更新日:Dec 04, 2025

SQL クエリに DISTINCT オペレーターが含まれている場合、データベースはソートまたはハッシュ化を使用して重複行を削除します。この操作は、特に大規模なデータセットの場合、多くの CPU およびメモリリソースを消費する可能性があります。多くのシナリオでは、SELECT リストにプライマリキーが含まれている場合など、クエリ結果はすでに一意です。このような場合、DISTINCT 操作は冗長になります。PolarDB for MySQL のオプティマイザーは、テーブルスキーマとクエリ条件の関数従属性を分析することで、冗長な DISTINCT 操作を識別して排除します。この機能は、不要な計算を削減し、クエリの実行時間、CPU 使用量、メモリ使用量を低減します。

仕組み

この最適化の中核となるのは、関数従属性の概念です。関数従属性とは、テーブルの 1 つ以上の列の値が、他の 1 つ以上の列の値を一意に決定することを意味します。例えば、テーブルのプライマリキーは、そのテーブル内の他のすべての列を一意に決定します。

オプティマイザーが DISTINCT を含むクエリを分析する際、プライマリキーや一意なインデックスなどのテーブルのメタデータとクエリ条件を使用して一意性を推論します。オプティマイザーが射影列 (SELECT 列) の列の組み合わせがすでに一意な結果を保証すると判断した場合、実行計画から DISTINCT オペレーターを削除します。

適用範囲

  • クラスターバージョン

    • 製品シリーズ: Cluster EditionStandard Edition

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

  • 機能範囲

    • 射影列に一意キーが含まれる場合: SELECT 文の列にテーブルの一意キー (プライマリキーまたは一意なインデックスを構成するすべての列) が含まれている場合、結果セットの一意性が保証されます。

      -- user_id が users テーブルのプライマリキーであると仮定します
      SELECT DISTINCT user_id, user_name FROM users; -- DISTINCT は排除可能です
    • 射影列が関数従属的に一意キーに依存する場合: SELECT 文のすべての列が一意キーによって一意に決定される場合、クエリ結果も一意になります。これは通常、単一テーブルのクエリや、ファクトテーブルとの 1 対 1 または多対 1 の結合で発生します。

      -- user_id がプライマリキーであり、(user_name, email) が user_id によって一意に決定されると仮定します
      SELECT DISTINCT user_name, email FROM users WHERE user_id = 123; -- DISTINCT は排除可能です
    • すべての射影列が定数である場合: SELECT 文のすべての列が定数である場合、結果セットには最大で 1 行しか含まれません。この場合、DISTINCT の使用は冗長です。オプティマイザーは DISTINCT を削除し、LIMIT 1 を追加します。

      SELECT DISTINCT 'hello', 123 FROM t1 WHERE a = 1; -- DISTINCT は排除可能で、LIMIT 1 が追加されます
    • UNION DISTINCT クエリ: UNION DISTINCT クエリにおいて、UNION 内の各 SELECT 文の結果セットがすでに一意である場合、オプティマイザーはこれらの内部 SELECT 文に対する DISTINCT 操作を排除できます。

    説明

    オプティマイザーは、一意性を推論する際に NOT NULL 制約を厳密に考慮します。一意キーの列が NULL である可能性がある場合、一意性の判断に影響を与え、オプティマイザーが DISTINCT を排除できなくなることがあります。

DISTINCT 排除機能の有効化

distinct_elimination_mode パラメーターを設定して、この最適化機能の動作を制御します。

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

  • PolarDB コンソール の場合

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

    • 手順loose_ プレフィックスが付いているパラメーターを見つけて変更します。

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

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

パラメーター

レベル

説明

loose_distinct_elimination_mode

グローバル/セッション

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

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

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

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

最適化シナリオの例

DISTINCT 排除機能が有効になっていることを確認するには、EXPLAIN コマンドを使用してクエリの実行計画を表示します。最適化が有効な場合、実行計画にはソートやハッシュベースの重複排除など、DISTINCT 処理のためのオペレーターは含まれません。以下のセクションでは、典型的な最適化シナリオについて説明します。

シナリオ 1:射影列が定数である場合

オプティマイザーが射影列が定数であることを識別すると、DISTINCT を排除し、LIMIT 1 を追加できます。

  1. データの準備t1 テーブルを作成し、データを挿入します。

    CREATE TABLE testdb.t1 (a INT, b INT);
    INSERT INTO testdb.t1 VALUES (1, 10), (1, 20);
  2. 元のクエリの実行

    EXPLAIN SELECT DISTINCT a + 1 FROM testdb.t1 WHERE a = 1;
  3. 最適化の検証: 最適化された実行計画で、warnings の情報を確認します。DISTINCT 操作が排除されています。

    SHOW warnings;
    +-------+------+-------------------------------------------------------------------------------------------------------------------+
    | Level | Code | Message                                                                                                           |
    +-------+------+-------------------------------------------------------------------------------------------------------------------+
    | Note  | 1003 | /* select#1 */ select (`testdb`.`t1`.`a` + 1) AS `a + 1` from `testdb`.`t1` where (`testdb`.`t1`.`a` = 1) limit 1 |
    +-------+------+-------------------------------------------------------------------------------------------------------------------+

シナリオ 2:関数従属性による一意性の推論

a が列 b を一意に決定し、かつ b が NULL でない一意キーである場合、オプティマイザーは a も一意であると推論できます。これにより、DISTINCT を排除できます。

  1. データの準備t2 テーブルを作成します。ここで、列 b は列 a から生成され、一意です。

    CREATE TABLE t2 (
      a INT,
      b INT AS (a + 1) UNIQUE
    );
    INSERT INTO t2(a) VALUES (10), (20);
  2. 元のクエリの実行

    EXPLAIN SELECT DISTINCT a FROM t2 WHERE b IS NOT NULL;
  3. 最適化の検証b の一意性が結果における a の一意性を保証するため、DISTINCT は削除されます。warnings の情報を確認します:

    SHOW warnings;
    +-------+------+---------------------------------------------------------------------------------------------------------+
    | Level | Code | Message                                                                                                 |
    +-------+------+---------------------------------------------------------------------------------------------------------+
    | Note  | 1003 | /* select#1 */ select `testdb`.`t2`.`a` AS `a` from `testdb`.`t2` where (`testdb`.`t2`.`b` is not null) |
    +-------+------+---------------------------------------------------------------------------------------------------------+

シナリオ 3:サブクエリの結果が自然に一意である場合

サブクエリ dt が一意キー c を含むため自然に一意である場合、JOIN 操作後も結果の一意性が保たれることがあります。これにより、オプティマイザーは外部の DISTINCT を排除できます。

  1. データの準備t3 テーブルを作成します。ここで、列 cab から生成され、一意です。

    CREATE TABLE t3 (
      a INT NOT NULL,
      b INT NOT NULL,
      c INT AS (a + b) UNIQUE
    );
    INSERT INTO t3(a, b) VALUES (1, 10), (2, 20);
  2. 元のクエリの実行

    EXPLAIN SELECT DISTINCT a, b FROM (SELECT a, b, c FROM t3) dt, (SELECT a AS d FROM t3 limit 1) dt2 WHERE c IS NOT NULL;
  3. 最適化の検証: 最適化された実行計画で、warnings の情報を確認します。DISTINCT 操作が排除されています。

    SHOW warnings;                                                                                                 
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------+
    | Level | Code | Message                                                                                                                          |
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------+
    | Note  | 1003 | /* select#1 */ select `testdb`.`t3`.`a` AS `a`,`testdb`.`t3`.`b` AS `b` from `testdb`.`t3` where (`testdb`.`t3`.`c` is not null) |
    +-------+------+----------------------------------------------------------------------------------------------------------------------------------+

パフォーマンス

DISTINCT 排除機能を有効にすると、典型的なシナリオで大幅なパフォーマンス向上が見られます:

メトリック

パフォーマンス向上

実行時間

10% から 60% 削減。

メモリ使用量

20% から 70% 削減。

CPU 使用率

ハッシュ化またはソート操作による CPU オーバーヘッドを削減します。