system.query_log を使用して繰り返し発生する低速クエリのパターンを特定し、代表的な実行を選択してリソース使用状況を確認する方法を説明します。次に、クエリやスキーマを変更する前に、EXPLAIN を使用してクエリプランを確認し、ボトルネックに関する仮説を立てます。
始める前に
nyc_taxi.trips_small_inferred テーブルを使用します。記載どおりに実行するには、まだ作成・読み込みを行っていない場合は、以下の手順を実行してください。
サンプルデータセットをセットアップする
サンプルデータセットをセットアップする
元のParquetファイルは約5.8 GBです。ネットワーク環境や利用可能なリソースによっては、読み込みに数分かかる場合があります。
SYSTEM FLUSH LOGS を実行できない場合は、クエリログが自動的にフラッシュされるのを待ってから、最初のルックアップを再試行してください。自身のワークロードを診断する際は、system.query_log に確認する時間範囲の完了済み実行が含まれていることを確認してください。
仕組み
system.query_log テーブルに記録します。各レコードには、クエリの実行時間、読み取った行数、CPU とメモリの使用量、ファイルシステムキャッシュのアクティビティが含まれます。
これらの測定値は、低速クエリパターンを特定し、リソースの使用状況を把握するのに役立ちます。代表的な実行を選択したら、そのクエリプランを調べて、クエリの処理時間がかかっている箇所を確認できます。
クラスターでは、クエリログデータは各ノードにローカルに保持されます。このガイドの例では、すべてのレプリカをクエリするために clusterAllReplicas を使用し、現在の system.query_log テーブルと、システムテーブルのスキーマ変更後も保持されるバージョン付き query_log_N テーブルを含めるために merge を使用します。
各クエリログの例には、クラスター化されたデプロイメント用と単一ノードのデプロイメント用のタブがあります。ClickHouse Cloud では、クラスターの例で default クラスターを使用します。セルフマネージドデプロイメントでは、default を system.clusters に一覧表示されているクラスターに置き換えてください。
例では
skip_unavailable_shards を設定し、一時的に使用不可となったレプリカが原因で診断クエリが失敗しないようにしています。これはオートスケーリング中に特に役立ちます。スキップされたレプリカのレコードは含まれないため、結果が不完全になる場合があります。低速クエリを診断する
候補となるクエリを特定する
まず、完了した初回クエリを
normalized_query_hash でグループ化します。これにより、繰り返し発生するクエリパターンと、単発の遅い実行とを切り分けられます。次のクエリは、パターンを実行時間の中央値順にランク付けし、各パターンのサンプルクエリを併せて表示します。- クラスター
- 単一ノード
executions を使用すると、繰り返し発生するワークロードと単発のクエリを区別できます。実行時間の中央値が大きい、実行回数が多い、またはリソース使用量が多いパターンは、単発の遅い実行よりも調査対象として有力な候補となります。簡単な棚卸しとして、次のクエリは NYC Taxi dataset に対する最大 5 種類の異なる query patterns について、最も遅い完了済み実行を一覧表示します。dataset を読み込む文や、同一 pattern の繰り返し実行は除外されます。次の step では、上で選択した normalized_query_hash を持つ実行にクエリ履歴を絞り込みます。- クラスター
- 単一ノード
query_duration_ms フィールドには、クエリの実行時間がミリ秒単位で格納されます。この結果では、最も実行時間の長いクエリで 2,967 ms かかっています。クエリの実行時間ではなく、リソース使用量に基づいて候補となるクエリを特定することもできます:リソースを大量に消費するクエリを特定する
リソースを大量に消費するクエリを特定する
このクエリでは、最近実行されたクエリをメモリ使用量順にランキングし、CPU 使用量も表示します。結果はワークロードとデプロイメントによって異なります。
- クラスター
- 単一ノード
代表的なクエリ実行を選択する
1 回だけ遅い実行があった場合、アドホッククエリや一時的なシステム負荷による外れ値である可能性があります。クエリプランを調べる前に、リテラル値だけが異なるクエリでは同じ値となる クエリログ結果の例では、各候補が約3億2,904万行を読み取ったことが示されています。参考として、例のテーブルの行数を確認してください。このテーブルには3億2,904万行が含まれており、各候補の
normalized_query_hash を持つ完了済みの実行を複数確認してください。そのパターンにおける典型的な実行時間とリソース使用量を示す実行を選択します。selected_hash に設定されている値を、調査したいパターンの normalized_query_hash に置き換えます。- クラスター
- 単一ノード
read_rowsとread_bytesが近い実行を見つけます。- それらの実行の
query_duration_msとmemory_usageを比較します。 query_duration_msが中央値に最も近いquery_idを選択します。
過去のクエリログの結果は、cache の状態やシステム負荷によって変動する可能性があります。そのため、最適化による変更の比較には使用せず、調査対象のクエリを選ぶために使用してください。クエリログに完了済みの実行が十分にない場合は、同様の条件下でクエリを数回実行してください。次のガイド「クエリのボトルネックを特定する」では、変更を比較するための制御された測定値を収集する方法を説明します。
read_rows で報告された行数とほぼ同じです。これは、クエリがテーブルの大部分または全体をスキャンしたことを示唆していますが、これらの行が読み取られた理由や、その量がクエリに対して適切かどうかはわかりません。次にクエリプランを調べ、ClickHouse がデータをどのように選択・処理したかを確認します。実行計画を確認する
代表的な実行を選択したら、出力には、次の操作が含まれます。パーツ数やグラニュール数などの詳細は、データの保存方法によって異なります。下から順に見ると、このプランはクエリの各処理に次のように対応しています。
EXPLAIN を使用して、クエリを実行せずに ClickHouse がどのようなクエリ実行計画を立てるかを確認します。出力には、ClickHouse が実行すると見込む操作と、それらの間でデータがどのように移動するかが表示され、クエリログ内の測定値を理解するための詳細なコンテキストが得られます。使用可能な出力フォーマットの詳しい説明については、アナライザによるクエリ実行の理解 を参照してください。この例では、EXPLAIN により、ClickHouse がデータの読み取りとフィルタリングをどのように計画しているか、またデータの一部をスキップできるかどうかが示されます。出力は、ClickHouse がデータをどのように読み取り、フィルタリングし、処理すると見込んでいるかを示す操作のツリーです。子操作は親操作の下に表示されます。最も深い読み取り操作から始め、計画を上へたどって、ClickHouse がデータを最終結果にどのように変換するかを確認します。この例では、クエリログの結果にある計算速度クエリを確認します。ReadFromMergeTreeはnyc_taxi.trips_small_inferredからデータを読み取ります。Indexesセクションがなく、read_rowsがテーブルの行数と一致していることから、ClickHouse がテーブル全体を読み取っていることが分かります。Filterは、speed_mph > 30の展開後の式を示します。読み取った各行について、ClickHouse は乗車時間と速度を計算し、時速 30 マイルを超える行だけを残します。Aggregatingは、フィルタリング後のtrip_distanceの値から分位点を計算します。
speed_mph の計算、分位点の計算です。