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

PolarDB:実行計画と基本演算子

最終更新日:Jun 03, 2024

このトピックでは、EXPLAINコマンドを実行して実行計画をクエリする方法について説明し、LogicalViewGatherMergeSortなどの基本演算子を紹介します。 Join、Agg、Sortなどのその他の演算子については、フォローアップのトピックで個別に説明します。

背景情報

通常、SQLチューニングには次の2つの手順が必要です。

  1. 問題を分析します。 たとえば、問題を分析するには、EXPLAINコマンドを実行して実行計画を表示します。また、EXPLAIN analyzeを使用して実際の実行ステータスを表示することもできます。 詳細については、「クエリ実行プログラムの概要」をご参照ください。
  2. ヒントを使用してオプティマイザの動作を制御し、実行計画を変更します。

実行計画とEXPLAINコマンド

次の例では、EXPLAINコマンドを実行してクエリの実行計画を取得する方法について説明します。

EXPLAINの構文は次のとおりです。

説明 ヒントEXPLAINの隣に配置する必要があります。
EXPLAIN <SQL文>
EXPLAIN <ヒント> <SQL文> 

このトピックのすべての例は、次のスキーマに基づいています。

テーブル 'sbtest1' の作成 (
  'id' INT(10) UNSIGNED NOT NULL、
  'k' INT(10) 未署名NOT NULLデフォルト '0' 、
  'c' CHAR(120) NOT NULL DEFAULT ''、
  'pad'CHAR (60) NOT NULL DEFAULT ''、
  キー 'xid' ('id') 、
  キー 'k_1 ' ('k')
) dbpartition BY HASH ('id') tbpartition BY HASH ('id') tbpartitions 4 

次のEXPLAINコマンドを実行すると、PolarDB-X 1.0は対応する実行プランを返します。

mysql> explain select a.k、count(*) cnt from sbtest1a、sbtest1bここでa.id = b.kおよびa.id > 1000を有するkによるcntグループ> 1300によるcnt limit 5、10;
+ --------------------------------------------------------------------------------------------------------------------------------------------------- +
| ローカルプラン |
+ --------------------------------------------------------------------------------------------------------------------------------------------------- +
| MemSort(sort="cnt ASC", offset=? 2、fetch=? 3) |
| フィルター (条件="cnt > ? 1 ") |
| HashAgg(group="k", cnt="COUNT()") |
| BKAJoin(id="id" 、k="k" 、c="c" 、pad="pad" 、id0="id0" 、k0="k0" 、c0="c0" 、pad0="pad0" 、condition="id = k" 、type="inner" |)
| MergeSort(sort="k ASC") |
| LogicalView(tables="[0000-0031].sbtest1_[000-127]" 、shardCount=128、sql="SELECT * FROM 'sbtest1' WHERE ('id' > ?) ORDER BY 'k'") |
| 収集 (同時=true) |
| LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM 'sbtest1' WHERE (('k' > ?)) AND ('k' IN ('?')))") |
| HitCache:false |
+ --------------------------------------------------------------------------------------------------------------------------------------------------- +
セットの9行 (0.01秒) 

実行計画に加えて、EXPLAINの結果にはいくつかの追加情報が含まれています。 上記の例では、プランキャッシュがヒットしたかどうかを示すHitCacheのみが追加情報として含まれています。 詳細な原則については、「実行計画の管理」をご参照ください。

オペレーターの概要

PolarDB-X 1.0は、次の演算子をサポートしています。

意味物理演算子
クエリの配信LogicalViewLogicalModifyView、およびPhyTableOperation
参加BKAJoinNLJoinHashJoinSortMergeJoinHashSemiJoinSortMergeSemiJoin、およびMaterializedSemiJoin
ソートMemSortTopN
集計 (グループ別)HashAggSortAgg
データ交換収集MergeSort
その他ProjectFilterLimitUnionWindow

以下のセクションでは、演算子の一部の意味と実装について説明します。 残りの演算子については、フォローアップのトピックで説明します。

LogicalView

LogicalView演算子は、データソースとして機能するストレージレイヤーMySQLからデータを取得します。 LogicalViewは、他のデータベースのTableScanまたはIndexScanに似ていますが、より多くのプッシュダウン操作をサポートします。 LogicalViewには、プッシュダウンされたSQL文とデータソース情報が含まれており、ビューに似ています。 プッシュダウンされるSQLステートメントには、Project、Filter、aggregation、sorting、Join、サブクエリなど、複数の種類の演算子が含まれる場合があります。 次の例は、EXPLAINコマンドのLogicalViewの出力情報と意味を示しています。

> explain select * sbtest1からid > 1000;

収集 (concurrent=true)
   LogicalView(tables="[0000-0031].sbtest1_[000-127]" 、shardCount=128、sql="SELECT * FROM 'sbtest1' WHERE ('id' > ?)") 

LogicalViewの情報は3つの部分で構成されています。

  • tables: ストレージレイヤーMySQLに対応するテーブル名。 tablesパラメーターの値は、ピリオド (.) で分割されます。 ピリオドの前の情報 (.) は、データベースシャーディングに対応するIDを指定し、ピリオドの後の情報 (.) は、テーブル名とそのIDを指定します。 たとえば、[000-127] は、テーブル名IDが000〜127のすべてのテーブルを示します。
  • shardCount: アクセスするテーブルシャーディングの総数。 この例では、IDが000から127の範囲の128テーブルシャーディングがアクセスされます。
  • sql: ストレージ層MySQLに配信されるSQLテンプレート。PolarDB-X 1.0実行中、PolarDB-X 1.0はテーブル名を物理テーブルの名前に置き換え、パラメーター化された定数疑問符 (?) を実際のパラメーターに置き換えます。 詳細については、「実行プランの管理」をご参照ください。

収集

収集は、複数のデータセットを1つのデータセットにマージします。 上記の例では、Gather演算子は、すべてのテーブルシャーディングから取得したデータを1つのデータセットにマージします。

並列クエリが無効になっている場合、Gather演算子は通常LogicalViewの上に表示されます。 これは、Gather演算子がすべてのテーブルシャーディングのデータを収集してマージすることを示します。 並列クエリが有効になっている場合、Gather演算子をより高い位置に引き上げることができます。 この場合、Gather演算子はすべてのWorkerの計算結果を収集してマージします。

Gather演算子のconcurrentパラメーターは、サブ演算子を同時に実行するかどうかを指定します。 デフォルト値はtrueです。 これは、データが同時にプルされることを示す。 並列クエリが有効になっている場合、プルアップされるGather演算子の属性が変更され、parallel=trueと表示されます。

MergeSort

MergeSortは、順序付きデータストリームを1つの順序付きデータストリームにマージおよびソートするマージソート演算子です。 例:

> explain select * from sbtest1 where id > 1000 order by id limit 5,10;

MergeSort(sort="id ASC", offset=? 1、fetch=? 2)
  LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM 'sbtest1' WHERE ('id' > ?) ORDER BY 'id' LIMIT (?? + ?)")

MergeSort演算子は、次の3つの部分で構成されます。

  • sort: 並べ替えフィールドと並べ替え順序。 id ASCはIDフィールドによる昇順のソートを示し、DESCは降順のソートを示します。
  • offset: 結果セットが取得されたときのオフセット。 この例の値はパラメータ化されています。 実際の値は5です。
  • fetch: 返されるデータ行の最大数。 このパラメーターの値はパラメーター化されています。 これは、オフセットパラメータの値と同様である。 実際の値は10です。

プロジェクト

Project: 投影操作。 つまり、入力データから一部の列を選択して出力したり、一部の列を変換 (関数や式で計算) して出力したりする。 Project演算子には定数を含めることもできます。

> explain select 'Hello, DRDS', 1 / 2, CURTIME();

プロジェクト (Hello, DRDS="_UTF-16 'Hello, DRDS'", 1 / 2="1/2", CURTIME()="CURTIME()") 

Project演算子のプランには、各列の名前と、対応する列、値、関数、または式が含まれます。

フィルター

Filter演算子は、フィルタリング操作を示し、いくつかのフィルタ条件を含みます。 この演算子は入力データをフィルタリングします。 データが条件を満たす場合、データは出力として返されます。 そうでなければ、データは破棄される。 次の複雑な例には、前述の演算子のほとんどが含まれます。

> sbtest1からk、avg(id) avg_idを選択すると説明します。id > 1000> 1300を持つkによってグループ化されます。フィルター (条件="avg_id > ? 1 ")
  プロジェクト (k="k", avg_id="sum_pushed_sum / sum_pushed_count")
    SortAgg(group="k", sum_pushed_sum="SUM(pushed_sum)", sum_pushed_count="SUM(pushed_count)")
      MergeSort(sort="k ASC")
        LogicalView(tables="[0000-0031].sbtest1_[000-127]" 、shardCount=128、sql="SELECT 'k' 、SUM('id') AS 'pushed_sum' 、COUNT('id') AS 'pushed_count' FROM 'sbtest1' WHERE ('id'>) 'k' ORDER 'k'? 

WHERE id > 1000条件に対応するフィルター操作がない理由は、フィルター演算子がLogicalViewに押し下げられているためです。 LogicalViewのSQL文でWHERE (id > ?) を表示できます。

Union AllとUnion Distinct

名前が示すように、Union AllはUNIONALLに対応し、Union DistinctはUNIONDISTINCTに対応します。 これらの演算子は通常2つ以上の入力を有する。 これは、演算子が複数の入力のデータをマージすることを示します。 例:

> explain select * From sbtest1 where id > 1000 union distinct select * From sbtest1 where id < 200;

UnionDistinct (同時=true)
  収集 (concurrent=true)
    LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM 'sbtest1' WHERE ('id' > ?)")
  収集 (concurrent=true)
    LogicalView(tables="[0000-0031].sbtest1_[000-127]" 、shardCount=128、sql="SELECT * FROM 'sbtest1' WHERE ('id' < ?)") 

LogicalModifyView

前のセクションでは、LogicalView演算子が基になるデータソースからデータを取得することについて説明しました。 一方、LogicalModifyView演算子は、基になるデータソースを変更します。 LogicalModifyViewは、SQLステートメントも記録します。 SQLステートメントは、INSERTUPDATE、またはDELETEです。

> update sbtest1 set c='Hello、DRS 'について説明します。id > 1000;

LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="UPDATE 'sbtest1' SET 'c' = ? どこ ('id' > ?)" 
> sbtest1からの削除の説明id > 1000;

LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="DELETE FROM 'sbtest1' WHERE ('id' > ?)") 

LogicalModifyViewのクエリプランの内容は、LogicalViewの内容と似ています。これには、配信された物理テーブルのシャーリング、テーブルのシャーリング数、SQLテンプレートが含まれます。 同様に、実行プランキャッシュが有効になっており、SQLステートメントがパラメータ化されているため、SQLテンプレートの定数は疑問符 (?) に置き換えられます。

PhyTableOperation

PhyTableOperation演算子は、物理テーブルシャーディングに対する操作を直接実行します。

説明 通常、この演算子はINSERT文でのみ使用されます。 ただし、SQLステートメントがシャードにルーティングされる場合、この演算子はSELECTステートメントにも表示されます。
> sbtest1値への挿入 (1、1、'1' 、'1') 、(2、2、'2' 、'2') について説明します。PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_001]", sql="INSERT INTO? ('id' 、'k' 、'c' 、'pad') VALUES(? 、? 、? 、?)"、params=" 'sbtest1_001 '、1,1、1,1 ")
PhyTableOperation(tables="SYSBENCH_CORONADB_1526954857179TGMMSYSBENCH_CORONADB_VGOC_0000_RDS.[sbtest1_002]", sql="INSERT INTO? ('id' 、'k' 、'c' 、'pad') VALUES(? 、? 、? 、?)"、params=" 'sbtest1_002 '、2,2、2,2 ") 

この例では、INSERT文は2行のデータを挿入します。 データの各行は、PhyTableOperation演算子に対応します。 PhyTableOperation演算子の内容は3つの部分で構成されています。

  • tables: 物理テーブルの名前。 物理テーブルの名前は1つだけ指定されています。
  • sql: SQLテンプレート。 SQLテンプレートのすべてのテーブル名と定数はパラメータ化され、疑問符? 対応するパラメータは、後続のparamsパラメータで提供されます。
  • params: テーブル名と定数を含む、SQLテンプレートに対応するパラメーター。