ApsaraDB for SelectDB'de herhangi bir SQL sorgusunun yürütme planını görüntülemek için EXPLAIN deyimlerini kullanın. Her biri farklı düzeyde ayrıntı sunan üç varyant bulunur:
İpucu:EXPLAIN GRAPH<EXPLAIN<EXPLAIN VERBOSE— her varyant, öncekinden daha fazla ayrıntı döndürür.
| Varyant | Çıktı |
|---|---|
EXPLAIN GRAPH SELECT veya DESC GRAPH SELECT |
Yürütme planı ağacının ve parçalarının görsel grafiği |
EXPLAIN SELECT |
Düğüm başına ayrıntılar (aşağı itilen filtre koşulları ve tarama istatistikleri gibi) içeren metin tabanlı plan |
EXPLAIN VERBOSE SELECT |
Tam ayrıntı: EXPLAIN SELECT çıktısına ek olarak demet tanımlayıcıları, yuva tanımlayıcıları ve çalışma zamanı filtre atamaları |
EXPLAIN, SQL deyimini derler ancak çalıştırmaz. Hesaplama kaynağı tüketmez ve sorgu sonucu döndürmez.
Nasıl çalışır
SQL bildirimsel bir dildir; verilerin ne olduğunu belirtir, nasıl alınacağını değil. Sorgu planlayıcısı; hangi birleştirme algoritmasının kullanılacağını (Hash Join, Sort Merge Join, Shuffle Join veya Broadcast Join), Kartezyen çarpımı önlemek için en uygun birleştirme sırasını ve her işlemin hangi düğümlerde çalıştırılacağını belirleyerek yürütme yöntemini karar verir.
Sorgu planlayıcısı önce bağımsız bir yürütme planı ağacı oluşturur, ardından bunu birden çok plan parçasından oluşan dağıtılmış bir yürütme planına dönüştürür. Her parça planın bir bölümünü işler. Veriler ExchangeNode operatörü aracılığıyla parçalar arasında aktarılır. Her parça ayrıca kaynak kullanımını ve sorgu eşzamanlılığını en üst düzeye çıkarmak için paralel çalışan birden çok örneğe bölünür.
Aşağıdaki diyagram basit bir bağımsız yürütme planı ağacını gösterir:
┌────┐
│Sort│
└────┘
│
┌───────────┐
│Aggregation│
└───────────┘
│
┌────┐
│Join│
└────┘
┌───┴────┐
┌──────┐ ┌──────┐
│Scan-1│ │Scan-2│
└──────┘ └──────┘
Sorgu planlayıcısı bu yapıyı dağıtılmış bir plana dönüştürdüğünde ağacı parçalara böler. Aşağıdaki diyagram, aralarında veri aktaran bir ExchangeNode ile aynı planın iki parçaya (F1 ve F2) bölünmüş halini gösterir:
┌────┐
│Sort│
│F1 │
└────┘
│
┌───────────┐
│Aggregation│
│F1 │
└───────────┘
│
┌────┐
│Join│
│F1 │
└────┘
┌──────┴────┐
┌──────┐ ┌────────────┐
│Scan-1│ │ExchangeNode│
│F1 │ │F1 │
└──────┘ └────────────┘
│
┌──────────────┐
│DataStreamSink│
│F2 │
└──────────────┘
│
┌──────┐
│Scan-2│
│F2 │
└──────┘
EXPLAIN GRAPH SELECT veya DESC GRAPH SELECT
EXPLAIN GRAPH SELECT ve DESC GRAPH SELECT eşdeğerdir. İkisi de yürütme planını görsel bir ağaç olarak sunar; böylece her düğümün hangi parçaya ait olduğu ve parçaların birbirine nasıl bağlandığı kolayca görülür.
EXPLAIN GRAPH SELECT tbl1.k1, SUM(tbl1.k2)
FROM tbl1 JOIN tbl2 ON tbl1.k1 = tbl2.k1
GROUP BY tbl1.k1
ORDER BY tbl1.k1;
Çıktı:
+---------------------------------------------------------------------------------------------------------------------------------+
| Explain String |
+---------------------------------------------------------------------------------------------------------------------------------+
| |
| ┌───────────────┐ |
| │[9: ResultSink]│ |
| │[Fragment: 4] │ |
| │RESULT SINK │ |
| └───────────────┘ |
| │ |
| ┌─────────────────────┐ |
| │[9: MERGING-EXCHANGE]│ |
| │[Fragment: 4] │ |
| └─────────────────────┘ |
| │ |
| ┌───────────────────┐ |
| │[9: DataStreamSink]│ |
| │[Fragment: 3] │ |
| │STREAM DATA SINK │ |
| │ EXCHANGE ID: 09 │ |
| │ UNPARTITIONED │ |
| └───────────────────┘ |
| │ |
| ┌─────────────┐ |
| │[4: TOP-N] │ |
| │[Fragment: 3]│ |
| └─────────────┘ |
| │ |
| ┌───────────────────────────────┐ |
| │[8: AGGREGATE (merge finalize)]│ |
| │[Fragment: 3] │ |
| └───────────────────────────────┘ |
| │ |
| ┌─────────────┐ |
| │[7: EXCHANGE]│ |
| │[Fragment: 3]│ |
| └─────────────┘ |
| │ |
| ┌───────────────────┐ |
| │[7: DataStreamSink]│ |
| │[Fragment: 2] │ |
| │STREAM DATA SINK │ |
| │ EXCHANGE ID: 07 │ |
| │ HASH_PARTITIONED │ |
| └───────────────────┘ |
| │ |
| ┌─────────────────────────────────┐ |
| │[3: AGGREGATE (update serialize)]│ |
| │[Fragment: 2] │ |
| │STREAMING │ |
| └─────────────────────────────────┘ |
| │ |
| ┌─────────────────────────────────┐ |
| │[2: HASH JOIN] │ |
| │[Fragment: 2] │ |
| │join op: INNER JOIN (PARTITIONED)│ |
| └─────────────────────────────────┘ |
| ┌──────────┴──────────┐ |
| ┌─────────────┐ ┌─────────────┐ |
| │[5: EXCHANGE]│ │[6: EXCHANGE]│ |
| │[Fragment: 2]│ │[Fragment: 2]│ |
| └─────────────┘ └─────────────┘ |
| │ │ |
| ┌───────────────────┐ ┌───────────────────┐ |
| │[5: DataStreamSink]│ │[6: DataStreamSink]│ |
| │[Fragment: 0] │ │[Fragment: 1] │ |
| │STREAM DATA SINK │ │STREAM DATA SINK │ |
| │ EXCHANGE ID: 05 │ │ EXCHANGE ID: 06 │ |
| │ HASH_PARTITIONED │ │ HASH_PARTITIONED │ |
| └───────────────────┘ └───────────────────┘ |
| │ │ |
| ┌─────────────────┐ ┌─────────────────┐ |
| │[0: OlapScanNode]│ │[1: OlapScanNode]│ |
| │[Fragment: 0] │ │[Fragment: 1] │ |
| │TABLE: tbl1 │ │TABLE: tbl2 │ |
| └─────────────────┘ └─────────────────┘ |
+---------------------------------------------------------------------------------------------------------------------------------+
Plan beş parçaya (Parça 0'dan Parça 4'e kadar) ayrılır. Her düğümdeki [Fragment: N] etiketi düğümün ait olduğu parçayı gösterir. DataStreamSink ve ExchangeNode düğümleri parçalar arasındaki veri iletimini yönetir.
EXPLAIN SELECT
EXPLAIN SELECT komutu, grafik görünümünde yer almayan düğüm başına ayrıntıları (aşağı itilen filtre koşulları ve tarama başına istatistikler dahil) içeren metin tabanlı bir plan döndürür.
EXPLAIN SELECT tbl1.k1, sum(tbl1.k2)
FROM tbl1 JOIN tbl2 ON tbl1.k1 = tbl2.k1
GROUP BY tbl1.k1
ORDER BY tbl1.k1;
Çıktı:
+----------------------------------------------------------------------------------+
| EXPLAIN String |
+----------------------------------------------------------------------------------+
| PLAN FRAGMENT 0 |
| OUTPUT EXPRS:<slot 5> <slot 3> `tbl1`.`k1` | <slot 6> <slot 4> sum(`tbl1`.`k2`) |
| PARTITION: UNPARTITIONED |
| |
| RESULT SINK |
| |
| 9:MERGING-EXCHANGE |
| limit: 65535 |
| |
| PLAN FRAGMENT 1 |
| OUTPUT EXPRS: |
| PARTITION: HASH_PARTITIONED: <slot 3> `tbl1`.`k1` |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 09 |
| UNPARTITIONED |
| |
| 4:TOP-N |
| | order by: <slot 5> <slot 3> `tbl1`.`k1` ASC |
| | offset: 0 |
| | limit: 65535 |
| | |
| 8:AGGREGATE (merge finalize) |
| | output: sum(<slot 4> sum(`tbl1`.`k2`)) |
| | group by: <slot 3> `tbl1`.`k1` |
| | cardinality=-1 |
| | |
| 7:EXCHANGE |
| |
| PLAN FRAGMENT 2 |
| OUTPUT EXPRS: |
| PARTITION: HASH_PARTITIONED: `tbl1`.`k1` |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 07 |
| HASH_PARTITIONED: <slot 3> `tbl1`.`k1` |
| |
| 3:AGGREGATE (update serialize) |
| | STREAMING |
| | output: sum(`tbl1`.`k2`) |
| | group by: `tbl1`.`k1` |
| | cardinality=-1 |
| | |
| 2:HASH JOIN |
| | join op: INNER JOIN (PARTITIONED) |
| | runtime filter: false |
| | hash predicates: |
| | colocate: false, reason: table not in the same group |
| | equal join conjunct: `tbl1`.`k1` = `tbl2`.`k1` |
| | cardinality=2 |
| | |
| |----6:EXCHANGE |
| | |
| 5:EXCHANGE |
| |
| PLAN FRAGMENT 3 |
| OUTPUT EXPRS: |
| PARTITION: RANDOM |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 06 |
| HASH_PARTITIONED: `tbl2`.`k1` |
| |
| 1:OlapScanNode |
| TABLE: tbl2 |
| PREAGGREGATION: ON |
| partitions=1/1 |
| rollup: tbl2 |
| tabletRatio=3/3 |
| tabletList=105104776,105104780,105104784 |
| cardinality=1 |
| avgRowSize=4.0 |
| numNodes=6 |
| |
| PLAN FRAGMENT 4 |
| OUTPUT EXPRS: |
| PARTITION: RANDOM |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 05 |
| HASH_PARTITIONED: `tbl1`.`k1` |
| |
| 0:OlapScanNode |
| TABLE: tbl1 |
| PREAGGREGATION: ON |
| partitions=1/1 |
| rollup: tbl1 |
| tabletRatio=3/3 |
| tabletList=105104752,105104763,105104767 |
| cardinality=2 |
| avgRowSize=8.0 |
| numNodes=6 |
+----------------------------------------------------------------------------------+
Çıktı alanları
EXPLAIN SELECT çıktısında aşağıdaki alanlar yer alır:
| Alan | Açıklama |
|---|---|
PARTITION |
Parça için veri bölümlendirme stratejisi: RANDOM, HASH_PARTITIONED veya UNPARTITIONED |
EXCHANGE ID |
Bir DataStreamSink'i karşılık gelen ExchangeNode'a bağlayan tanımlayıcı |
cardinality |
Düğüm için tahmini satır sayısı. -1 değeri istatistiklerin olmadığını gösterir |
avgRowSize |
Taralı bir satırın bayt cinsinden ortalama boyutu |
numNodes |
Taramayı çalıştıran düğüm sayısı |
tabletRatio |
Taralı tabletlerin toplam tabletlere oranı (scanned/total) |
tabletList |
Taranacak tablet kimliklerinin virgülle ayrılmış listesi |
PREAGGREGATION |
Depolama katmanı ön toplamasının etkin olup olmadığı (ON veya OFF) |
rollup |
Tarama için kullanılan Rollup dizini |
colocate |
Birleştirmenin birlikte yerleştirme modunu kullanıp kullanmadığı. false ise neden gösterilir |
runtime filter |
Bu birleştirmeye bir çalışma zamanı filtresinin uygulanıp uygulanmadığı |
EXPLAIN VERBOSE SELECT
EXPLAIN VERBOSE SELECT en ayrıntılı çıktıyı döndürür. EXPLAIN SELECT içindeki tüm bilgilere ek olarak demet tanımlayıcılarını, yuva tanımlayıcılarını ve çalışma zamanı filtre atamalarını içerir. Operatörler vektörize edilmiş yürütme motorunu belirtmek için V önekini kullanır (örneğin, VHASH JOIN, VOlapScanNode).
EXPLAIN VERBOSE SELECT tbl1.k1, sum(tbl1.k2)
FROM tbl1 JOIN tbl2 ON tbl1.k1 = tbl2.k1
GROUP BY tbl1.k1
ORDER BY tbl1.k1;
Çıktı:
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN String |
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
| PLAN FRAGMENT 0 |
| OUTPUT EXPRS:<slot 5> <slot 3> `tbl1`.`k1` | <slot 6> <slot 4> sum(`tbl1`.`k2`) |
| PARTITION: UNPARTITIONED |
| |
| VRESULT SINK |
| |
| 6:VMERGING-EXCHANGE |
| limit: 65535 |
| tuple ids: 3 |
| |
| PLAN FRAGMENT 1 |
| |
| PARTITION: HASH_PARTITIONED: `default_cluster:test`.`tbl1`.`k2` |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 06 |
| UNPARTITIONED |
| |
| 4:VTOP-N |
| | order by: <slot 5> <slot 3> `tbl1`.`k1` ASC |
| | offset: 0 |
| | limit: 65535 |
| | tuple ids: 3 |
| | |
| 3:VAGGREGATE (update finalize) |
| | output: sum(<slot 8>) |
| | group by: <slot 7> |
| | cardinality=-1 |
| | tuple ids: 2 |
| | |
| 2:VHASH JOIN |
| | join op: INNER JOIN(BROADCAST)[Tables are not in the same group] |
| | equal join conjunct: CAST(`tbl1`.`k1` AS DATETIME) = `tbl2`.`k1` |
| | runtime filters: RF000[in_or_bloom] <- `tbl2`.`k1` |
| | cardinality=0 |
| | vec output tuple id: 4 | tuple ids: 0 1 |
| | |
| |----5:VEXCHANGE |
| | tuple ids: 1 |
| | |
| 0:VOlapScanNode |
| TABLE: tbl1(null), PREAGGREGATION: OFF. Reason: the type of agg on StorageEngine's Key column should only be MAX or MIN.agg expr: sum(`tbl1`.`k2`) |
| runtime filters: RF000[in_or_bloom] -> CAST(`tbl1`.`k1` AS DATETIME) |
| partitions=0/1, tablets=0/0, tabletList= |
| cardinality=0, avgRowSize=20.0, numNodes=1 |
| tuple ids: 0 |
| |
| PLAN FRAGMENT 2 |
| |
| PARTITION: HASH_PARTITIONED: `default_cluster:test`.`tbl2`.`k2` |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 05 |
| UNPARTITIONED |
| |
| 1:VOlapScanNode |
| TABLE: tbl2(null), PREAGGREGATION: OFF. Reason: null |
| partitions=0/1, tablets=0/0, tabletList= |
| cardinality=0, avgRowSize=16.0, numNodes=1 |
| tuple ids: 1 |
| |
| Tuples: |
| TupleDescriptor{id=0, tbl=tbl1, byteSize=32, materialized=true} |
| SlotDescriptor{id=0, col=k1, type=DATE} |
| parent=0 |
| materialized=true |
| byteSize=16 |
| byteOffset=16 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=1 |
| |
| SlotDescriptor{id=2, col=k2, type=INT} |
| parent=0 |
| materialized=true |
| byteSize=4 |
| byteOffset=0 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=0 |
| |
| |
| TupleDescriptor{id=1, tbl=tbl2, byteSize=16, materialized=true} |
| SlotDescriptor{id=1, col=k1, type=DATETIME} |
| parent=1 |
| materialized=true |
| byteSize=16 |
| byteOffset=0 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=0 |
| |
| |
| TupleDescriptor{id=2, tbl=null, byteSize=32, materialized=true} |
| SlotDescriptor{id=3, col=null, type=DATE} |
| parent=2 |
| materialized=true |
| byteSize=16 |
| byteOffset=16 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=1 |
| |
| SlotDescriptor{id=4, col=null, type=BIGINT} |
| parent=2 |
| materialized=true |
| byteSize=8 |
| byteOffset=0 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=0 |
| |
| |
| TupleDescriptor{id=3, tbl=null, byteSize=32, materialized=true} |
| SlotDescriptor{id=5, col=null, type=DATE} |
| parent=3 |
| materialized=true |
| byteSize=16 |
| byteOffset=16 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=1 |
| |
| SlotDescriptor{id=6, col=null, type=BIGINT} |
| parent=3 |
| materialized=true |
| byteSize=8 |
| byteOffset=0 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=0 |
| |
| |
| TupleDescriptor{id=4, tbl=null, byteSize=48, materialized=true} |
| SlotDescriptor{id=7, col=k1, type=DATE} |
| parent=4 |
| materialized=true |
| byteSize=16 |
| byteOffset=16 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=1 |
| |
| SlotDescriptor{id=8, col=k2, type=INT} |
| parent=4 |
| materialized=true |
| byteSize=4 |
| byteOffset=0 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=0 |
| |
| SlotDescriptor{id=9, col=k1, type=DATETIME} |
| parent=4 |
| materialized=true |
| byteSize=16 |
| byteOffset=32 |
| nullIndicatorByte=0 |
| nullIndicatorBit=-1 |
| slotIdx=2 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------+
160 rows in set (0.00 sec)
Sonundaki Tuples bölümü her bir TupleDescriptor öğesini ve bunların SlotDescriptor girişlerini listeler. Her yuva tanımlayıcısı plandaki bir sütunu veya ifadeyi veri türü, bayt boyutu, bellek ofseti ve null göstergesi konumu dahil olmak üzere tanımlar.
EXPLAIN VERBOSE içindeki ek çıktı alanları
| Alan | Açıklama |
|---|---|
tuple ids |
Bir düğüm tarafından üretilen veya tüketilen demetlerin kimlikleri |
vec output tuple id |
Bir birleştirme düğümü tarafından üretilen vektörize edilmiş çıktının demet kimliği |
runtime filters |
Çalışma zamanı filtre atamaları: <- işaretinin bulunduğu yerde filtre oluşturulur; -> işaretinin bulunduğu yerde uygulanır |
TupleDescriptor |
Bir satır yapısını (tablo, toplam bayt boyutu, somutlaştırma durumu) tanımlar |
SlotDescriptor |
Bir demet içindeki bir sütunu veya ifadeyi (veri türü, bayt boyutu, bellek ofseti, null göstergesi) tanımlar |
Kullanım notları
EXPLAIN mantıksal yürütme planını gösterir. Gerçek çalışma zamanı yürütme sırası çalışma zamanı filtresi budama gibi optimizasyonlar nedeniyle farklılık gösterebilir.
cardinalitydeğerleri tablo istatistiklerine dayalı tahminlerdir. İstatistikler güncel değil veya yoksacardinality=-1görünür.EXPLAIN SELECTiçindekitabletRatiovetabletListdeğerleri üst sınır tahminleridir. Bölüm budama gibi çalışma zamanı optimizasyonları fiilen taranan tablet sayısını azaltabilir.EXPLAIN VERBOSEçıktısındakiVönekli operatörler (VHASH JOIN,VOlapScanNodevb.) vektörize edilmiş yürütme motorunu gösterir.EXPLAIN SELECTçıktısındaki öneksiz operatörler vektörize edilmemiş motoru gösterir.