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

PolarDB:サブクエリの最適化と実行

最終更新日:May 27, 2024

サブクエリは、クエリのWHERE句またはHAVING句内にネストされたSELECTステートメントです。 このトピックでは、PolarDB-Xのクエリオプティマイザと実行プログラムがサブクエリを処理する方法について説明します。

Subquery

サブクエリは、外部クエリからの値を使用するかどうかに基づいて、非相関サブクエリまたは相関サブクエリに分類されます。 非相関サブクエリは、外部クエリの変数とは無関係に実行される。 ほとんどの場合、非相関サブクエリは1回だけ実行されます。 相関サブクエリは、外部クエリからの変数を使用します。 相関するサブクエリは、外部クエリからの変数の値を使用する必要があるため、入力行ごとに実行されます。
/* 相関のないサブクエリの例。 * /
SELECT * FROM lineitem WHERE l_partkey IN (SELECT p_partkey FROM part);

/* 相関サブクエリの例。 l_suppkeyは、外部クエリから参照される列です。 * /
SELECT * FROM lineitem WHERE l_partkey IN (SELECT ps_partkey FROM partsupp WHERE ps_suppkey = l_suppkey); 
PolarDB-XはほとんどのSQLサブクエリをサポートしています。 詳細については、「SQL制限」をご参照ください。

サブクエリの実行

PolarDB-Xは、一般的なサブクエリをSEMIJOINステートメントまたはJOINステートメントに変換して、実行効率を向上させることができます。 このようにして、大量のデータが含まれる場合、システムは入れ子になったパラメータのグループを反復する必要がなくなります。 これにより、実行コストが大幅に削減されます。 このサブクエリ変換方法は、ネスト解除と呼ばれます。

次の例は、PolarDB-Xが2つのサブクエリを実行計画内のJOINステートメントに置き換えてネスト解除する方法を示しています。
> EXPLAIN SELECT p_partkey, (
      SELECT COUNT(ps_partkey) FROM partsupp WHERE ps_suppkey = p_partkey
      ) supplier_countパートから;

プロジェクト (p_partkey="p_partkey", supplier_count="CASE(IS NULL($10), 0, $9)", cor=[$cor0])
  HashJoin(condition="p_partkey = ps_suppkey" 、type="left")
    収集 (concurrent=true)
      LogicalView(tables="part_[0-7]", shardCount=8, sql="SELECT * FROM 'part' AS 'part'")
    プロジェクト (count(ps_partkey)="count(ps_partkey)", ps_suppkey="ps_suppkey", count(ps_partkey)2="count(ps_partkey)")
      HashAgg(group="ps_suppkey", count(ps_partkey)="SUM(count(ps_partkey))")
        収集 (concurrent=true)
          LogicalView(tables="partsupp_[0-7]", shardCount=8, sql="SELECT 'ps_suppkey', COUNT('ps_partkey ') AS 'count(ps_partkey)' FROM 'partsuppu'AS 'partsupp''GROUP BY 'ps_suppkey') 

ただし、一部のシナリオでは、PolarDB-Xはサブクエリのネストを解除できません。 これらのシナリオでは、クエリはサブクエリが実行された後にのみ実行できます。 外部クエリが大量のデータを含む場合、反復は時間がかかることがある。

次の例では、特定の行でl_partkeyの値が50未満であるため、サブクエリのネストを解除できません。 したがって、PolarDB-Xはネストされた反復を実行します。 実行効率を向上させるために、OR条件を削除してSQL文を書き換えることを推奨します。
> EXPLAIN SELECT * FROM lineitem WHERE l_partkey IN (SELECT ps_partkey FROM partsupp WHERE ps_suppkey = l_suppkey) またはl_partkeyはありません

フィルター (条件="IS(in,[$1])[29612489] またはl_partkey < ?0")
  収集 (concurrent=true)
    LogicalView(tables="QIMU_0000_GROUP,QIMU_0001_GROUP.lineitem_[0-7]", shardCount=8, sql="SELECT * FROM 'lineitem' AS 'lineitem'")

>> 個々の相関サブクエリ: 29612489
収集 (concurrent=true)
  LogicalView(tables="QIMU_0000_GROUP,QIMU_0001_GROUP.partsupp_[0-7]", shardCount=8, sql="SELECT * FROM (SELECT 'ps_partkey' FROM 'partsupp' AS 'partsupp' WHERE ('ps_suppkey' = 'l_suppkey'))) AS 't0' WHERE (((('l_partkey' = 'ps_partkey'))) OR ('l_partkey' IS NULL) OR ('ps_partkey') NULL)