このトピックでは、実行計画における一般的なオペレーターと、各オペレーターの役割について説明します。
オペレーターリファレンス
| カテゴリ | オペレーター |
| データノードへのプッシュダウン | LogicalView、LogicalModifyView、PhyTableOperation、IndexScan |
| Join | BKAJoin、NLJoin、HashJoin、SortMergeJoin、HashSemiJoin、SortMergeSemiJoin、MaterializedSemiJoin |
| ソート | MemSort、TopN、MergeSort |
| 集約 (GROUP BY) | HashAgg、SortAgg |
| データの再配布または収集 | 交換、収集 |
| フィルター | Filter |
| プロジェクト | Project |
| 結果セットのマージ | UnionAll、UnionDistinct |
| 出力行の制限 (Limit/Offset...Fetch) | Limit |
| ウィンドウ関数 | OverWindow |
データノードにプッシュダウンされるオペレーター
LogicalView
LogicalView は、ストレージレイヤーの MySQL データソースからデータを読み取ります。これは、他のデータベースの TableScan や IndexScan に似ていますが、より広範なプッシュダウン操作をサポートしています。LogicalView には、プッシュダウンされた SQL ステートメントとデータソース情報が含まれており、よりビューのように動作します。プッシュダウンされた SQL には、Project、Filter、集約、ソート、Join、サブクエリ操作が含まれる場合があります。次の例は、LogicalView の出力を示し、各フィールドについて説明します。
explain select * From sbtest1 where id > 1000;
出力:
Gather(concurrent=true)
LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)")LogicalView は 3 つの部分で構成されます。- tables:ストレージレイヤーの MySQL におけるテーブル名で、ピリオド
.で区切られます。ピリオド.の前はデータベースシャード番号、後はシャード番号を含むテーブル名です。例えば、[000-127] はシャード番号が 000 から 127 までのすべてのテーブルを表します。 - shardCount:アクセスするテーブルシャードの総数です。この例では、000 から 127 までの 128 個のテーブルシャードにアクセスします。
- sql:ストレージレイヤーの MySQL に送信される SQL テンプレートです。PolarDB-X のランタイムでは、テーブル名は物理テーブル名に置き換えられ、パラメーター化された定数プレースホルダー
?は実際のパラメーター値に置き換えられます。詳細については、「実行計画管理」をご参照ください。
LogicalModifyView
- 例 1
explain update sbtest1 set c='Hello, DRDS' where id > 1000;出力:
LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="UPDATE `sbtest1` SET `c` = ? WHERE (`id` > ?)" - 例 2
explain delete from sbtest1 where id > 1000;出力:
LogicalModifyView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="DELETE FROM `sbtest1` WHERE (`id` > ?)")
?に置き換えられます。PhyTableOperation
PhyTableOperation は、単一の物理テーブルシャードに対して直接操作を実行します。
explain insert into sbtest1 values(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 つの行を挿入し、各行は 1 つの PhyTableOperation オペレーターに対応します。PhyTableOperation は 3 つの部分で構成されます。- tables:物理テーブル名です。各 PhyTableOperation は、正確に 1 つの物理テーブルを対象とします。
- sql:SQL テンプレートです。このテンプレートでは、テーブル名と定数がパラメーター化され、
?に置き換えられます。対応するパラメーター値は、後続の params フィールドで提供されます。 - params:テーブル名と定数を含む、SQL テンプレートのパラメーター値です。
IndexScan
IndexScan は、LogicalView と同様に、インデックステーブルをスキャンしてストレージレイヤーの MySQL データソースからデータを読み取ります。次の例は、IndexScan の出力を示し、各フィールドについて説明します。
explain select * from sequence_one_base where integer_test=1;
出力:
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| IndexScan(tables="DRDS_POLARX1_QATEST_APP_000000_GROUP.gsi_sequence_one_index_3a0A_01", sql="SELECT `pk`, `integer_test`, `varchar_test`, `char_test`, `blob_test`, `tinyint_test`, `tinyint_1bit_test`, `smallint_test`, `mediumint_test`, `bit_test`, `bigint_test`, `float_test`, `double_test`, `decimal_test`, `date_test`, `time_test`, `datetime_test`, `timestamp_test`, `year_test`, `mediumtext_test` FROM `gsi_dml_sequence_one_index_index1` AS `gsi_dml_sequence_one_index_index1` WHERE (`integer_test` = ?)") |上記の SQL ステートメントは、通常、sequence_one_base テーブルをスキャンします。integer_test はパーティションキーではないため、sequence_one_base のすべてのシャードをスキャンする必要があります。しかし、sequence_one_base テーブルには integer_test 列に gsi_sequence_one_index という名前のグローバルセカンダリインデックス (GSI) があるため、述語 integer_test=1 を使用してインデックステーブルをプルーニングします。その結果、IndexScan オペレーターが生成され、gsi_sequence_one_index テーブルの 1 つのシャードのみをスキャンします。
計算ノードまたはデータノードで実行されるオペレーター
UnionAll と UnionDistinct
UnionAll は UNION ALL に対応し、UnionDistinct は UNION DISTINCT に対応します。このオペレーターは通常、2 つ以上の入力を持ち、複数の入力からのデータを 1 つにマージします。例:
explain select * From sbtest1 where id > 1000 union distinct select * From sbtest1 where id < 200;
出力:
UnionDistinct(concurrent=true)
Gather(concurrent=true)
LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` > ?)")
Gather(concurrent=true)
LogicalView(tables="[0000-0031].sbtest1_[000-127]", shardCount=128, sql="SELECT * FROM `sbtest1` WHERE (`id` < ?)")
Gather
Gather は、複数のデータストリームを単一のデータストリームにマージします。上記の例では、Gather は各テーブルシャードから収集されたデータを 1 つの結果セットにマージします。Gather は通常、LogicalView の上に表示され、スキャンされたすべてのシャードからデータを収集します。
Exchange
- SINGLETON:複数の上流データストリームを 1 つの出力ストリームにマージします。この戦略は Gather と同等です。
- HASH_DISTRIBUTED:特定の列によって上流の入力データを再パーティション化します。この戦略は、Join および Agg オペレーターを含む実行計画で一般的に使用されます。
- BROADCAST_DISTRIBUTED:上流データの単一のコピーを複数の後続ノードに配布します。この戦略は、主に MPP 実行計画で使用されます。
MergeSort
MergeSort は、複数のソート済みデータストリームを単一のソート済みデータストリームにマージするマージソートオペレーターです。例:
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:返す行の最大数です。offset と同様に、値はパラメーター化されており、実際の値は 10 です。
Project
Project は射影操作を実行します。これは、入力データから特定の列を選択して出力するか、出力前に関数や式を通じて特定の列を変換します。定数を含めることもできます。
explain select '你好, DRDS', 1 / 2, CURTIME();
出力:
Project(你好, DRDS="_UTF-16'你好, DRDS'", 1 / 2="1 / 2", CURTIME()="CURTIME()")フィルター
フィルターは、入力データにフィルター条件を適用します。条件を満たす行は通過し、それ以外の行は破棄されます。以下に、前述のオペレーターのほとんどを含む複雑な例を示します。
explain select k, avg(id) avg_id from sbtest1 where id > 1000 group by k having avg_id > 1300;出力:
Filter(condition="avg_id > ?1")
Project(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` > ?) GROUP BY `k` ORDER BY `k`")WHERE id>1000WHERE (id > ?)