Apache Doris プロフィール&詳しく解説
1. 簡単な紹介
Apache Doris で EXPLAIN + SQL を実行して、SQL に対応するクエリ プランを取得します。Apache Doris のプロファイルと組み合わせると、Doris が SQL ステートメントをどのように処理するかを理解できます。これは、クエリ ステートメントや構造のパフォーマンスのボトルネックを分析するために使用されます。より適切なインデックスを選択し、より最適化されたクエリ ステートメントを作成するのに役立ちます。
2. 計画分析
2.1 SQLの準備
tpcds query96.sql の例
explain
-- explain graph 生成对应执行计划图表
select count(*)
from store_sales
,household_demographics
,time_dim
, store
where ss_sold_time_sk = time_dim.t_time_sk
and ss_hdemo_sk = household_demographics.hd_demo_sk
and ss_store_sk = s_store_sk
and time_dim.t_hour = 8
and time_dim.t_minute >= 30
and household_demographics.hd_dep_count = 5
and store.s_store_name = 'ese'
order by count(*) limit 100;
2.2 結果分析の説明
クエリ プランは論理的な実行プラン (Logical Query Plan) と物理的な実行プラン (Physical Query Plan) に分けられます。現在のクエリ プランはデフォルトで論理的な実行プランを指します。tpcds query96.sql に対応するクエリ プランを以下に示します。
-- graph
┌───────────────┐
│[8: ResultSink]│
│[Fragment: 4] │
│RESULT SINK │
└───────────────┘
│
│
┌─────────────┐
│[8: TOP-N] │
│[Fragment: 4]│
└─────────────┘
│
│
┌────────────────────────────────┐
│[13: AGGREGATE (merge finalize)]│
│[Fragment: 4] │
└────────────────────────────────┘
│
│
┌──────────────┐
│[12: EXCHANGE]│
│[Fragment: 4] │
└──────────────┘
│
│
┌────────────────────┐
│[12: DataStreamSink]│
│[Fragment: 0] │
│STREAM DATA SINK │
│ EXCHANGE ID: 12 │
│ UNPARTITIONED │
└────────────────────┘
│
│
┌─────────────────────────────────┐
│[7: AGGREGATE (update serialize)]│
│[Fragment: 0] │
└─────────────────────────────────┘
│
│
┌───────────────────────────────┐
│[6: HASH JOIN] │
│[Fragment: 0] │
│join op: INNER JOIN (BROADCAST)│
└───────────────────────────────┘
┌───────────┴─────────────────────────────────────┐
│ │
┌───────────────────────────────┐ ┌──────────────┐
│[4: HASH JOIN] │ │[11: EXCHANGE]│
│[Fragment: 0] │ │[Fragment: 0] │
│join op: INNER JOIN (BROADCAST)│ └──────────────┘
└───────────────────────────────┘ │
┌───────────────┴─────────────────────┐ │
│ │ ┌────────────────────┐
┌───────────────────────────────┐ ┌──────────────┐ │[11: DataStreamSink]│
│[2: HASH JOIN] │ │[10: EXCHANGE]│ │[Fragment: 3] │
│[Fragment: 0] │ │[Fragment: 0] │ │STREAM DATA SINK │
│join op: INNER JOIN (BROADCAST)│ └──────────────┘ │ EXCHANGE ID: 11 │
└───────────────────────────────┘ │ │ UNPARTITIONED │
┌─────────┴──────────┐ │ └────────────────────┘
│ │ ┌────────────────────┐ ┌┘
┌──────────────────┐ ┌─────────────┐ │[10: DataStreamSink]│ │
│[0: OlapScanNode] │ │[9: EXCHANGE]│ │[Fragment: 2] │ ┌─────────────────┐
│[Fragment: 0] │ │[Fragment: 0]│ │STREAM DATA SINK │ │[5: OlapScanNode]│
│TABLE: store_sales│ └─────────────┘ │ EXCHANGE ID: 10 │ │[Fragment: 3] │
└──────────────────┘ │ │ UNPARTITIONED │ │TABLE: store │
│ └────────────────────┘ └─────────────────┘
┌───────────────────┐ │
│[9: DataStreamSink]│ │
│[Fragment: 1] │ ┌─────────────────────────────┐
│STREAM DATA SINK │ │[3: OlapScanNode] │
│ EXCHANGE ID: 09 │ │[Fragment: 2] │
│ UNPARTITIONED │ │TABLE: household_demographics│
└───────────────────┘ └─────────────────────────────┘
│
│
┌─────────────────┐
│[1: OlapScanNode]│
│[Fragment: 1] │
│TABLE: time_dim │
└─────────────────┘
-- 非graph
PLAN FRAGMENT 0
OUTPUT EXPRS:<slot 11> <slot 10> count(*)
PARTITION: UNPARTITIONED
RESULT SINK
8:TOP-N
| order by: <slot 11> <slot 10> count(*) ASC
| offset: 0
| limit: 100
|
13:AGGREGATE (merge finalize)
| output: count(<slot 10> count(*))
| group by:
| cardinality=-1
|
12:EXCHANGE
PLAN FRAGMENT 1
OUTPUT EXPRS:
PARTITION: HASH_PARTITIONED: `default_cluster:tpcds`.`store_sales`.`ss_item_sk`, `default_cluster:tpcds`.`store_sales`.`ss_ticket_number`
STREAM DATA SINK
EXCHANGE ID: 12
UNPARTITIONED
7:AGGREGATE (update serialize)
| output: count(*)
| group by:
| cardinality=1
|
6:HASH JOIN
| join op: INNER JOIN (BROADCAST)
| hash predicates:
| colocate: false, reason: Tables are not in the same group
| equal join conjunct: `ss_store_sk` = `s_store_sk`
| runtime filters: RF000[in] <- `s_store_sk`
| cardinality=2880403
|
|----11:EXCHANGE
|
4:HASH JOIN
| join op: INNER JOIN (BROADCAST)
| hash predicates:
| colocate: false, reason: Tables are not in the same group
| equal join conjunct: `ss_hdemo_sk` = `household_demographics`.`hd_demo_sk`
| runtime filters: RF001[in] <- `household_demographics`.`hd_demo_sk`
| cardinality=2880403
|
|----10:EXCHANGE
|
2:HASH JOIN
| join op: INNER JOIN (BROADCAST)
| hash predicates:
| colocate: false, reason: Tables are not in the same group
| equal join conjunct: `ss_sold_time_sk` = `time_dim`.`t_time_sk`
| runtime filters: RF002[in] <- `time_dim`.`t_time_sk`
| cardinality=2880403
|
|----9:EXCHANGE
|
0:OlapScanNode
TABLE: store_sales
PREAGGREGATION: OFF. Reason: conjunct on `ss_sold_time_sk` which is StorageEngine value column
PREDICATES: `default_cluster:tpcds.store_sales`.`__DORIS_DELETE_SIGN__` = 0
runtime filters: RF000[in] -> `ss_store_sk`, RF001[in] -> `ss_hdemo_sk`, RF002[in] -> `ss_sold_time_sk`
partitions=1/1
rollup: store_sales
tabletRatio=3/3
tabletList=20968,20972,20976
cardinality=2880403
avgRowSize=67.95811
numNodes=3
PLAN FRAGMENT 2
OUTPUT EXPRS:
PARTITION: HASH_PARTITIONED: `default_cluster:tpcds`.`store`.`s_store_sk`
STREAM DATA SINK
EXCHANGE ID: 11
UNPARTITIONED
5:OlapScanNode
TABLE: store
PREAGGREGATION: OFF. Reason: null
PREDICATES: `store`.`s_store_name` = 'ese', `default_cluster:tpcds.store`.`__DORIS_DELETE_SIGN__` = 0
partitions=1/1
rollup: store
tabletRatio=3/3
tabletList=20773,20777,20781
cardinality=23
avgRowSize=1798.8695
numNodes=3
PLAN FRAGMENT 3
OUTPUT EXPRS:
PARTITION: HASH_PARTITIONED: `default_cluster:tpcds`.`household_demographics`.`hd_demo_sk`
STREAM DATA SINK
EXCHANGE ID: 10
UNPARTITIONED
3:OlapScanNode
TABLE: household_demographics
PREAGGREGATION: OFF. Reason: null
PREDICATES: `household_demographics`.`hd_dep_count` = 5, `default_cluster:tpcds.household_demographics`.`__DORIS_DELETE_SIGN__` = 0
partitions=1/1
rollup: household_demographics
tabletRatio=3/3
tabletList=20848,20852,20856
cardinality=14399
avgRowSize=2.8781166
numNodes=3
PLAN FRAGMENT 4
OUTPUT EXPRS:
PARTITION: HASH_PARTITIONED: `default_cluster:tpcds`.`time_dim`.`t_time_sk`
STREAM DATA SINK
EXCHANGE ID: 09
UNPARTITIONED
1:OlapScanNode
TABLE: time_dim
PREAGGREGATION: OFF. Reason: null
PREDICATES: `time_dim`.`t_hour` = 8, `time_dim`.`t_minute` >= 30, `default_cluster:tpcds.time_dim`.`__DORIS_DELETE_SIGN__` = 0
partitions=1/1
rollup: time_dim
tabletRatio=3/3
tabletList=20713,20717,20721
cardinality=172799
avgRowSize=11.671202
numNodes=3
2.2.1 共通属性の説明
Colocate Join は、複数のテーブルが同じフィールドに従ってバケットに分割され、同じフィールドに基づいて頻繁に結合されるシナリオに適しています。たとえば、多くの電子商取引アプリケーションは、マーチャント ID に従ってバケットに分割され、マーチャント ID に従って頻繁に結合されます。販売者ID。
2.2.2 計画分析
-
Query96 のクエリ プランは、0 から 4 までの番号が付けられた 5 つのプラン フラグメントに分割されています。
-
分析クエリプランはボトムアップ方式で実行でき、1つずつ分析できます。
-
一番下の計画フラグメントはフラグメント 4 の分析です
- 主に time_dim テーブルをスキャンし、関連するクエリ条件を事前に実行する (述語プッシュダウン) ことを担当します。
- 集計テーブル (集計キー) について、doris はさまざまなクエリに応じて PREAGGREGATION を有効にするかどうかを選択します。上図の time_dim の事前集計はオフになっています。オフにすると、time_dim のすべてのディメンション列が読み取られます。テーブルに多くのディメンション列がある場合、これがパフォーマンスに影響を与える重要な要素になる可能性があります。
- time_dim テーブルでデータ パーティション化に範囲パーティションを選択した場合、クエリ プラン内のパーティションはクエリがヒットしたパーティションの数を示し、無関係なパーティションの自動フィルタリングにより、スキャンされるデータの量が効果的に削減されます。
- マテリアライズド ビューがある場合、doris はクエリに従ってマテリアライズド ビューを自動的に選択します。マテリアライズド ビューがない場合、クエリは自動的にベース テーブル (上図に示すロールアップ: time_dim) にヒットします。マテリアライズドビューをテストするためにドリスに送信
- time_dim データ スキャンが完了すると、フラグメント 4 の実行プロセスが終了します。この時点で、スキャンされたデータが他のフラグメントに渡されます。EXCHANGE ID: 09 は、データが 9 というラベルの受信ノードに渡されることを意味します。グラフビューを渡すことができます
-
Query96 のクエリ プランの場合、フラグメント 2、3、および 4 は同様の機能を持ちますが、スキャンを担当するテーブルが異なります。具体的には、クエリ内の Order/Aggregation/Join 演算子はすべてフラグメント 1 で実行され、フラグメント 1 の分析は実行されます。集中している
- フラグメント 1 は、実行にデフォルトの BROADCAST メソッドを使用して 3 つの結合演算子の実行を統合します。つまり、小さなテーブルが大きなテーブルにブロードキャストされます。2 つの結合テーブルが両方とも大きなテーブルである場合は、SHUFFLE メソッドを使用することをお勧めします。
- 現在、doris は HASH JOIN のみをサポートしています。つまり、結合にはハッシュ アルゴリズムが使用されます。
- colocate フィールドがあり、2 つの結合テーブルが同じパーティション/バケット方式を採用していることを示すために使用され、データを移動せずに結合プロセスをローカルで直接実行できます。
- Joinの実行が完了したら、上記のAggregation、Order by、TOP-Nの演算子を実行します。
3. ドリスプロフィールの簡単な紹介
8030 ページの QueryProfile モジュールを介してタスク実行の詳細を表示できます。以下は、query96.sql によって実際に実行される QueryProfile の一部です。各インジケーター名の詳細については、「Apache Doris クエリ分析」を参照してください。
Query:
Summary:
- Query ID: 7dd4ba245012441c-b0aadbed39f80f20
- Start Time: 2022-04-15 15:52:22
- End Time: 2022-04-15 15:52:22
- Total: 611ms
- Query Type: Query
- Query State: EOF
- Doris Version: 0.15.0-rc04
- User: root
- Default Db: default_cluster:tpcds
- Sql Statement: /* ApplicationName=DBeaver Enterprise 7.0.0 - SQLEditor <20220321常用命令-doris.sql> */ select count(*)
from store_sales
,household_demographics
,time_dim
, store
where ss_sold_time_sk = time_dim.t_time_sk
and ss_hdemo_sk = household_demographics.hd_demo_sk
and ss_store_sk = s_store_sk
and time_dim.t_hour = 8
and time_dim.t_minute >= 30
and household_demographics.hd_dep_count = 5
and store.s_store_name = 'ese'
order by count(*) limit 100
- Is Cached: No
Execution Summary:
- Analysis Time: 636.648us
- Plan Time: 19.230ms
- Schedule Time: 125.121ms
- Wait and Fetch Result Time: 466.30ms
Execution Profile 7dd4ba245012441c-b0aadbed39f80f20:(Active: 611.44ms, % non-child: 100.00%)
Fragment 0:
Instance 7dd4ba245012441c-b0aadbed39f80f2d (host=TNetworkAddress(hostname:10.192.119.70, port:9060)):(Active: 586.950ms, % non-child: 0.00%)
- FragmentCpuTime: 756.962us
- MemoryLimit: 2.00 GB
- PeakMemoryUsage: 48.01 KB
- PeakReservation: 0.00
- PeakUsedReservation: 0.00
- RowsProduced: 1
BlockMgr:
- BlockWritesOutstanding: 0
- BlocksCreated: 0
- BlocksRecycled: 0
- BufferedPins: 0
- BytesWritten: 0.00
- MaxBlockSize: 8.00 MB
- TotalBufferWaitTime: 0ns
- TotalEncryptionTime: 0ns
- TotalIntegrityCheckTime: 0ns
- TotalReadBlockTime: 0ns
DataBufferSender (dst_fragment_instance_id=7dd4ba245012441c-b0aadbed39f80f2d):
- AppendBatchTime: 124.481us
- ResultSendTime: 119.257us
- TupleConvertTime: 4.217us
- NumSentRows: 1
SORT_NODE (id=8):(Active: 587.36ms, % non-child: 0.01%)
- PeakMemoryUsage: 16.00 KB
- RowsReturned: 1
- RowsReturnedRate: 1
AGGREGATION_NODE (id=13):(Active: 586.958ms, % non-child: 0.10%)
- Probe Method: HashTable Linear Probing
- BuildTime: 10.533us
- GetResultsTime: 0ns
- HTResize: 0
- HTResizeTime: 0ns
- HashBuckets: 0
- HashCollisions: 0
- HashFailedProbe: 0
- HashFilledBuckets: 0
- HashProbe: 0
- HashTravelLength: 0
- LargestPartitionPercent: 0
- MaxPartitionLevel: 0
- NumRepartitions: 0
- PartitionsCreated: 0
- PeakMemoryUsage: 28.00 KB
- RowsProcessed: 0
- RowsRepartitioned: 0
- RowsReturned: 1
- RowsReturnedRate: 1
- SpilledPartitions: 0
EXCHANGE_NODE (id=12):(Active: 586.364ms, % non-child: 95.96%)
- BytesReceived: 32.00 B
- ConvertRowBatchTime: 7.320us
- DataArrivalWaitTime: 586.282ms
- DeserializeRowBatchTimer: 22.637us
- FirstBatchArrivalWaitTime: 349.530ms
- PeakMemoryUsage: 12.01 KB
- RowsReturned: 3
- RowsReturnedRate: 5
- SendersBlockedTotalTimer(*): 0ns
Fragment 1:
Instance 7dd4ba245012441c-b0aadbed39f80f23 (host=TNetworkAddress(hostname:10.192.119.68, port:9060)):(Active: 472.511ms, % non-child: 0.10%)
- FragmentCpuTime: 5.714ms
- MemoryLimit: 2.00 GB
- PeakMemoryUsage: 610.00 KB
- PeakReservation: 0.00
- PeakUsedReservation: 0.00
- RowsProduced: 1
BlockMgr:
- BlockWritesOutstanding: 0
- BlocksCreated: 0
- BlocksRecycled: 0
- BufferedPins: 0
- BytesWritten: 0.00
- MaxBlockSize: 8.00 MB
- TotalBufferWaitTime: 0ns
- TotalEncryptionTime: 0ns
- TotalIntegrityCheckTime: 0ns
- TotalReadBlockTime: 0ns
DataStreamSender (dst_id=12, dst_fragments=[7dd4ba245012441c-b0aadbed39f80f2d]):(Active: 186.357us, % non-child: 0.03%)
- BytesSent: 16.00 B
- IgnoreRows: 0
- LocalBytesSent: 0.00
- OverallThroughput: 83.84375 KB/sec
- PeakMemoryUsage: 16.00 KB
- SerializeBatchTime: 7.0us
- UncompressedRowBatchSize: 16.00 B
AGGREGATION_NODE (id=7):(Active: 471.713ms, % non-child: 0.14%)
- Probe Method: HashTable Linear Probing
- BuildTime: 45.223us
- GetResultsTime: 0ns
- HTResize: 0
- HTResizeTime: 0ns
- HashBuckets: 0
- HashCollisions: 0
- HashFailedProbe: 0
- HashFilledBuckets: 0
- HashProbe: 0
- HashTravelLength: 0
- LargestPartitionPercent: 0
- MaxPartitionLevel: 0
- NumRepartitions: 0
- PartitionsCreated: 0
- PeakMemoryUsage: 280.00 KB
- RowsProcessed: 0
- RowsRepartitioned: 0
- RowsReturned: 1
- RowsReturnedRate: 2
- SpilledPartitions: 0
HASH_JOIN_NODE (id=6):(Active: 470.881ms, % non-child: 0.08%)
- ExecOption: Hash Table Built Asynchronously
- BuildBuckets: 1.024K (1024)
- BuildRows: 1
- BuildTime: 1.129ms
- HashTableMaxList: 1
- HashTableMinList: 1
- LoadFactor: 4562146422526312400.00
- PeakMemoryUsage: 308.00 KB
- ProbeRows: 341
- ProbeTime: 34.697us
- PushDownComputeTime: 156.171us
- PushDownTime: 4.423us
- RowsReturned: 341
- RowsReturnedRate: 724
- アクティブ: ノード (そのすべての子ノードを含む) の実行時間を示します。
- BuildTime: 適切なテーブルをスキャンしてハッシュ テーブルを構築する時間
- ProbeTime: 左側のテーブルを取得し、一致するハッシュテーブルを検索して出力する時間