本文介紹了一些基本的運算元含義和實現。
運算元介紹
| 含義 | 運算元 |
| 可下推至DN的運算元 | LogicalView,LogicalModifyView,PhyTableOperation, IndexScan |
| 串連(Join) | BKAJoin,NLJoin,HashJoin,SortMergeJoin,HashSemiJoin,SortMergeSemiJoin,MaterializedSemiJoin |
| 排序 | MemSort,TopN, MergeSort |
| 彙總(Group By) | HashAgg,SortAgg |
| 資料重分布或者彙總 | Exchange、Gather |
| 過濾 | Filter |
| 投影 | Project |
| 求並集 | UnionAll、UnionDistinct |
| 設定結果集輸出行數(Limit/Offset...Fetch) | Limit |
| 視窗函數 | OverWindow |
可下推至DN執行的運算元
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的資訊由三部分構成:- 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插入兩行資料,每行資料對應一個PhyTableOperation運算元。PhyTableOperation運算元的內容包括三部分:- tables:物理表名,僅有唯一一個物理表名。
- sql: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,將integer_test=1作為謂詞條件對索引表做裁剪,實際上會產生IndexScan運算元,表示只會掃描gsi_sequence_one_index索引表的一個分區。可在CN或DN上執行的運算元
UnionAll與UnionDistinct
顧名思義,Union All對應UNIONALL,Union Distinct對應UNIONDISTINCT。該運算元通常有2個或更多個輸入,表示將多個輸入的資料合併在一起。例如:
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將各個分表上查詢到的資料合併成一份。Gather通常出現在LogicalView上方,表示收集合并各個分表的資料。
Exchange
- SINGLETON:將上遊多份資料進行合并輸出,這種重分布策略等價於Gather。
- HASH_DISTRIBUTED:將上遊輸入的資料按照某些列做repartition,常見於包含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運算元包含三部分內容:- 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()")Project的計劃中包括每列的列名及其對應的列、值、函數或者運算式。Filter
Filter表示過濾操作,其中包含一些過濾條件。該運算元對輸入資料進行過濾,若滿足條件,則輸出,否則丟棄。如下是一個較複雜的例子,包含了以上介紹的大部分運算元。
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>1000中的條件沒有對應的Filter運算元,是因為這個運算元最終被下推到了LogicalView中,可以在LogicalView的SQL中看到WHERE (id > ?)。