クエリプロファイルの構造とメトリクス
概要
クエリプロファイルは、StarRocks 内で SQL クエリの実行に関する詳細なレポートを提供します。クエリのパフォーマンスに関する包括的なビューを提供し、各操作に費やされた時間、処理されたデータ量、その他の関連メトリクスを含みます。この情報は、クエリパフォーマンスの最適化、ボトルネックの特定 、問題のトラブルシューティングに非常に役立ちます。
現実世界の遅いクエリの80%は、3つの警告メトリクスのいずれかを特定することで解決されます。このチートシートは、数値に溺れる前にあなたをそこに導きます。
クイックスタート
最近のクエリをプロファイルする:
1. 最近のクエリIDをリストする
クエリプロファイルを分析するには、クエリIDが必要です。SHOW PROFILELIST;
を使用します:
SHOW PROFILELIST;
SHOW PROFILELIST
の詳細は Text-based Query Profile Visualized Analysis に記載されています。始める際はそのページを参照してください。
2. SQLと並べてプロファイルを開く
ANALYZE PROFILE FOR <query_id>\G
を実行するか、CelerData Web UIでProfileをクリックします。
3. 「Execution Overview」バナーをざっと見る
全体の実行パフォーマンスのための主要なメトリクスを調べます:
- QueryExecutionWallTime: クエリ実行の総ウォールクロック時間
- QueryPeakMemoryUsagePerNode: ノードごとのピークメモリ使用量で、BEメモリの80%を超える値はデータスピルやメモリエラー(OOM)のリスクを示します
- QueryCumulativeCpuTime / WallTime < 0.5 * num_cpu_cores はCPUが待機していることを意味します(おそらくI/Oまたはネットワーク)
どれも発火しない場合、通常クエリは問題ありません—ここで終了します。
4. さらに深く掘り下げる
最も時間やメモリを消費するオペレーターを特定し、そのメトリクスを分析し、パフォーマンスボトルネックを特定するための根本原因を突き止めます。
「Operator Metrics」セクションは、パフォーマンス問題の根本原因を特定するための多くのガイドラインを提供します。
コアコンセプト
クエリ実行フロー
SQLクエリの包括的な実行フローは以下のステージを含みます:
- 計画: クエリは解析、分析、最適化を経て、クエリプランの生成に至ります。
- スケジューリング: スケジューラとコーディネータが協力して、クエリプランをすべての参加するバックエンドノードに分配します。
- 実行: クエリプランはパイプライン実行エンジンを使用して実行されます。
クエリプランの構造
StarRocksの実行エンジンは、クエリを分散方式で実行するように設計されており、クエリプロファイルの構造はこの設計を反映しています。分散クエリプランを構成するコンポーネントは以下の通りです:
- Fragment: 実行ツリーの最上位レベルで、論理的な作業単位を表します。クエリは1つ以上のフラグメントに分割されることがあります。
- FragmentInstance: 各フラグメントは複数回インスタンス化され、各インスタンス(FragmentInstance)は異なる計算ノードで実行されます。これにより、ノード間での並列処理が可能になります。
- Pipeline: FragmentInstanceはさらに複数のパイプラインに分割され、これらは接続されたOperatorインスタンスのシーケンスです。パイプラインはFragmentInstanceの実行パスを定義します。
- PipelineDriver: 計算リソースの利用を最大化するために、各パイプラインは複数のインスタンス(PipelineDriver)を持つことができます。これらのドライバーは、複数の計算コアを活用してパイプラインを並列に実行します。
- Operator: 基本的な実行単位であり、OperatorインスタンスはPipelineDriverの一部です。オペレーターは、集計、ジョイン、スキャンなどの特定のアルゴリズムを実装してデータを処理します。
パイプライン実行エンジンの概念
パイプラインエンジンは、StarRocks実行エンジンの主要コンポーネントです。クエリプランを並列かつ効率的に実行する責任を負っています。パイプラインエンジンは、複雑なクエリプランや大量のデータを処理するように設計されており、高いパフォーマンスとスケーラビリティを保証します。
パイプラインエンジンの主要な概念:
- Operator: 特定のアルゴリズム(例: 集計、ジョイン、スキャン)を実装する基本的な実行単位
- Pipeline: 実行パスを表す接続されたOperatorインスタンスのシーケンス
- PipelineDriver: 並列実行のためのパイプラインの複数のインスタンス
- Schedule: ユーザースペースのタイムスライシングを使用したパイプラインの非ブロッキングスケジューリング
メトリクスマージ戦略
デフォルトでは、StarRocksはプロファイルボリュームを削減するためにFragmentInstanceとPipelineDriverレイヤーをマージし、簡略化された3層構造を生成します:
- Fragment
- Pipeline
- Operator
このマージ動作は、セッション変数pipeline_profile_level
を通じて制御できます:
1
(デフォルト): マージされた3層構造2
: 元の5層構造- その他の値:
1
として扱われます
メトリクスをマージする際、メトリクスタイプに基づいて異なる戦略が使用されます:
-
時間関連のメトリクス: 平均を取る
- 例:
OperatorTotalTime
は平均時間消費 __MAX_OF_OperatorTotalTime
と__MIN_OF_OperatorTotalTime
は極値を記録
- 例:
-
非時間関連のメトリクス: 値を合計
- 例:
PullChunkNum
はすべてのインスタンスの合計 __MAX_OF_PullChunkNum
と__MIN_OF_PullChunkNum
は極値を記録
- 例:
-
定数メトリクス: すべてのインスタンスで同じ値(例:
DegreeOfParallelism
)
MINとMAX値の間に大きな違いがある場合、特に集計やジョイン操作においてデータの偏りを示すことがよくあります。
クエリプロファイルメトリクス
サマリーメトリクス
クエリ実行に関する基本情報:
メトリクス | 説明 |
---|---|
Total | クエリによって消費された総時間で、計画、実行、プロファイリングフェーズの期間を含みます。 |
Query State | クエリの状態。可能な状態には、Finished、Error、Runningがあります。 |
Query ID | クエリの一意の識別子。 |
Start Time | クエリが開始されたタイムスタンプ。 |
End Time | クエリが終了したタイムスタンプ。 |
Total | クエリの総期間。 |
Query Type | クエリのタイプ。 |
Query State | クエリの現在の状態。 |
StarRocks Version | 使用されたStarRocksのバージョン。 |
User | クエリを実行したユーザー。 |
Default Db | クエリで使用されたデフォルトデータベース。 |
Sql Statement | 実行されたSQLステートメント。 |
Variables | クエリで使用された重要な変数。 |
NonDefaultSessionVariables | クエリで使用された非デフォルトのセッション変数。 |
Collect Profile Time | プロファイルを収集するのにかかった時間。 |
IsProfileAsync | プロファイル収集が非同期であったかどうかを示します。 |
プランナーメトリクス
プランナーの包括的な概要を提供します。通常、プランナーに費やされる総時間が10ms未満の場合、問題はありません。
特定のシナリオでは、プランナーがより多くの時間を必要とする場合があります:
- 複雑なクエリは、最適な実行プランを確保するために、解析と最適化に追加の時間を 必要とする場合があります。
- 多数のマテリアライズドビューが存在する場合、クエリの書き換えに必要な時間が増加する可能性があります。
- 複数の同時クエリがシステムリソースを使い果たし、クエリキューが使用される場合、
Pending
時間が長引く可能性があります。 - 外部テーブルを含むクエリは、外部メタデータサーバーとの通信に追加の時間を要する可能性があります。
例:
- -- Parser[1] 0
- -- Total[1] 3ms
- -- Analyzer[1] 0
- -- Lock[1] 0
- -- AnalyzeDatabase[1] 0
- -- AnalyzeTemporaryTable[1] 0
- -- AnalyzeTable[1] 0
- -- Transformer[1] 0
- -- Optimizer[1] 1ms
- -- MVPreprocess[1] 0
- -- MVTextRewrite[1] 0
- -- RuleBaseOptimize[1] 0
- -- CostBaseOptimize[1] 0
- -- PhysicalRewrite[1] 0
- -- DynamicRewrite[1] 0
- -- PlanValidate[1] 0
- -- InputDependenciesChecker[1] 0
- -- TypeChecker[1] 0
- -- CTEUniqueChecker[1] 0
- -- ColumnReuseChecker[1] 0
- -- ExecPlanBuild[1] 0
- -- Pending[1] 0
- -- Prepare[1] 0
- -- Deploy[1] 2ms
- -- DeployLockInternalTime[1] 2ms
- -- DeploySerializeConcurrencyTime[2] 0
- -- DeployStageByStageTime[6] 0
- -- DeployWaitTime[6] 1ms
- -- DeployAsyncSendTime[2] 0
- DeployDataSize: 10916
Reason:
実行概要メトリクス
高レベルの実行統計:
メトリクス | 説明 | 目安 |
---|---|---|
FrontendProfileMergeTime | FE側のプロファイル処理時間 | < 10ms 正常 |
QueryAllocatedMemoryUsage | ノード全体での割り当てメモリの合計 | |
QueryDeallocatedMemoryUsage | ノード全体での解放メモリの合計 | |
QueryPeakMemoryUsagePerNode | ノードごとの最大ピークメモリ | < 80% 容量正常 |
QuerySumMemoryUsage | ノード全体でのピークメモリの合計 | |
QueryExecutionWallTime | 実行のウォール時間 | |
QueryCumulativeCpuTime | ノード全体でのCPU時間の合計 | walltime * totalCpuCores と比較 |
QueryCumulativeOperatorTime | オペレーター実行時間の合計 | オペレーター時間の割合の分母 |
QueryCumulativeNetworkTime | Exchangeノードのネットワーク時間の合計 | |
QueryCumulativeScanTime | ScanノードのIO時間の合計 | |
QueryPeakScheduleTime | 最大パイプラインスケジュール時間 | 単純なクエリの場合 < 1s 正常 |
QuerySpillBytes | ディスクにスピルされたデータ | < 1GB 正常 |
フラグメントメトリクス
フラグメントレベルの実行詳細:
メトリクス | 説明 |
---|---|
InstanceNum | FragmentInstancesの数 |
InstanceIds | すべてのFragmentInstancesのID |
BackendNum | 参加しているBEsの数 |
BackendAddresses | BEアドレス |
FragmentInstancePrepareTime | フラグメント準備フェーズの期間 |
InstanceAllocatedMemoryUsage | インスタンスの割り当てメモリの合計 |
InstanceDeallocatedMemoryUsage | インスタンスの解放メモリの合計 |
InstancePeakMemoryUsage | インスタンス全体でのピークメモリ |
パイプラインメトリクス
パイプラインの実行詳細と関係:
主要な関係:
- DriverTotalTime = ActiveTime + PendingTime + ScheduleTime
- ActiveTime = ∑ OperatorTotalTime + OverheadTime
- PendingTime = InputEmptyTime + OutputFullTime + PreconditionBlockTime + PendingFinishTime
- InputEmptyTime = FirstInputEmptyTime + FollowupInputEmptyTime
メトリクス | 説明 |
---|---|
DegreeOfParallelism | パイプライン実行の並行度。 |
TotalDegreeOfParallelism | 並行度の合計。同じパイプラインが複数のマシンで実行される可能性があるため、この項目はすべての値を集計します。 |
DriverPrepareTime | 準備フェーズにかかる時間。このメトリクスはDriverTotalTimeには含まれません。 |
DriverTotalTime | 準備フェーズを除くパイプラインの総実行時間。 |
ActiveTime | 各オペレーターの実行時間と、has_output、need_inputなどのメソッドの呼び出しに費やされる全体的なフレームワークオーバーヘッドを含むパイプラインの実行時間。 |
PendingTime | さまざまな理由でスケジュールされるのをブロックされているパイプラインの時間。 |
InputEmptyTime | 入力キューが空であるためにブロックされているパイプラインの時間。 |
FirstInputEmptyTime | 入力キューが空であるために最初にブロックされるパイプラインの時間。最初のブロック時間は、主にパイプラインの依存関係によって引き起こされるため、別途計算されます。 |
FollowupInputEmptyTime | 入力キューが空であるためにその後ブロックされるパイプラインの時間。 |
OutputFullTime | 出力キューが満杯であるためにブロックされるパイプラインの時間。 |
PreconditionBlockTime | 依存関係が満たされていないためにブロックされるパイプラインの時間。 |
PendingFinishTime | 非同期タスクの終了を待つためにブロックされているパイプラインの時間。 |
ScheduleTime | 準備完了キューに入ってから実行のためにスケジュールされるまでのパイプラインのスケジュール時間。 |
BlockByInputEmpty | InputEmptyのためにパイプラインがブロックされた回数。 |
BlockByOutputFull | OutputFullのためにパイプラインがブロックされた回数。 |
BlockByPrecondition | 未満の前提条件のためにパイプラインがブロックされた回数。 |
オペレーターメトリクス
メトリクス | 説明 |
---|---|
PrepareTime | 準備に費やされた時間。 |
OperatorTotalTime | オペレーターによって消費された総時間。これは次の式を満たします: OperatorTotalTime = PullTotalTime + PushTotalTime + SetFinishingTime + SetFinishedTime + CloseTime。準備に費やされた時間は含まれません。 |
PullTotalTime | オペレーターがpush_chunkを実行するのに費やす総時間。 |
PushTotalTime | オペレーターがpull_chunkを実行するのに費やす総時間。 |
SetFinishingTime | オペレーターがset_finishingを実行するのに費やす総時間。 |
SetFinishedTime | オペレーターがset_finishedを実行するのに費やす総時間。 |
PushRowNum | オペレーターの入力行の累積数。 |
PullRowNum | オペレーターの出力行の累積数。 |
JoinRuntimeFilterEvaluate | ジョインランタイムフィルターが評価された回数。 |
JoinRuntimeFilterHashTime | ジョインランタイムフィルターのハッシュを計算するのに費やされた時間。 |
JoinRuntimeFilterInputRows | ジョインランタイムフィルターの入力行数。 |
JoinRuntimeFilterOutputRows | ジョインランタイムフィルターの出力行数。 |
JoinRuntimeFilterTime | ジョインランタイムフィルターに費やされた時間。 |
スキャンオペレーター
スキャンオペレーター内のさまざまなメトリクスをよりよく理解するために、以下の図はこれらのメトリクスとストレージ構造との関連を示しています。
ディスクからデータを取得し、述語を適用するために、ストレージエンジンはいくつかの技術を利用します:
- データストレージ: エンコードおよび圧縮されたデータは、さまざまなインデックスと共にセグメントに保存されます。
- インデックスフィルタリング: エンジンは、BitmapIndex、BloomfilterIndex、ZonemapIndex、ShortKeyIndex、NGramIndexなどのインデックスを利用して不要なデータをスキップします。
- プッシュダウン述語:
a > 1
のような単純な述語は、特定の列で評価するためにプッシュダウンされます。 - 後期実体化: 必要な列とフィルタリングされた行のみがディスクから取得されます。
- 非プッシュダウン述語: プッシュダウンできない述語が評価されます。
- プロジェクション式:
SELECT a + 1
のような式が計算されます。
一般的なパフォーマンスボトルネックとその解決策:
重い生I/Oまたは遅いストレージ
警告メトリクス/症状: BytesRead、RawRowsRead、CompressedBytesRead、ScanTime、IOTaskExecTimeが支配的
OLAPスキャンを遅くする理由: ディスク(またはオブジェクトストア)の読み取り帯域幅が制約になる
解決策: ホットデータをNVMe/SSDに配置、ストレージキャッシュを有効化
不十分な述語
警告メトリクス/症状: PushdownPredicates≈0; ExprFilterRowsが支配的; LIKE '%x%'または他の複雑な述語
OLAPスキャンを遅くする理由: フィルタがストレージレイヤーで適用されないため、より多くの行がCPUスレッドプールに流れ込む
解決策: フィルタを単純な比較に書き換える、ターゲットとなるMVs/インデックスを構築
低DOPまたはスレッドプールの飽和
警告メトリクス/症状: 高いIOTaskWaitTime; 低いPeakIOTasks
OLAPスキャンを遅くする理由: 並列スキャンタスクが少なすぎるか、スレッドがI/Oスロットを待ってブロックされる
解決策: ディスク帯域幅を増やすか、キャッシュを拡大
BEs間のタブレット/データの偏り
警告メトリクス/症状: OperatorTotalTimeまたはBytesReadの大きな最大-最小ギャップ; 1つのタブレットがほとんどのデータを所有
OLAPスキャンを遅くする理由: 1つのスレッドが不均衡な作業を行い、他のスレッドはアイドル状態
解決策: 高カーディナリティキーでハッシュバケットを作成; バケット数を増やす
断片化されたRowsetsと小さなセグメント
警告メトリクス/症状: 高いRowsetsReadCount / SegmentsReadCount; 長いSegmentInit時間
OLAPスキャンを遅くする理由: 多くの小さなファイルが頻繁なオープン/シーク呼び出しを強制
解決策: コンパクションスレッドを増やすか、手動でコンパクションを実行; ミニロードをバッチ処理
ソフト削除されたレコードの数が多い
警告メトリクス/症状: 高いDeleteFilterRows
OLAPスキャンを遅くする理由: ソフト削除は読み取り時に削除述語を適用
解決策: データを圧縮; 削除操作の頻度を減らす
スキャンオペレーターは、IOタスクを実行するための追加のスレッドプールを利用します。したがって、このノードの時間メトリクス間の関係は以下のように示されます:
OLAPスキャンオペレーター
OLAP_SCANオペレーターは、StarRocks内部テーブルからデータを読み取る責任を負います。
メトリクス | 説明 |
---|---|
Table | テーブル名。 |
Rollup | マテリアライズドビュー名。マテリアライズドビューがヒットしない場合、テーブル名と同じです。 |
SharedScan | enable_shared_scanセッション変数が有効かどうか。 |
TabletCount | タブレットの数。 |
MorselsCount |