Kusto 照会言語 クエリのベスト プラクティス
適用対象: ✅Microsoft Fabric✅Azure データ エクスプローラー✅Azure Monitor✅Microsoft Sentinel
ここでは、クエリをより高速に実行するために従うべきいくつかのベスト プラクティスを示します。
要は
アクション | 使用 | 使用禁止 | メモ |
---|---|---|---|
クエリを実行するデータの量を減らす | where 演算子などのメカニズムを使用して、処理されるデータの量を減らします。 |
処理されるデータの量を減らす効率的な方法の詳細については、「 処理されるデータの量を削減するを参照してください。 | |
冗長な修飾参照の使用を避ける | ローカル エンティティを参照する場合は、修飾されていない名前を使用します。 | 詳細については、「冗長な修飾参照を使用 Avoidを参照してください。 | |
datetime 列 |
datetime データ型を使用します。 |
long データ型は使用しないでください。 |
クエリでは、 unixtime_milliseconds_todatetime() などの Unix 時刻変換関数を使用しないでください。 代わりに、更新ポリシーを使用して、インジェスト中に Unix 時間を datetime データ型に変換します。 |
文字列演算子 | has 演算子を使用する。 |
contains は使用しません |
完全なトークンを検索する場合は、サブ文字列を検索しない has の方が有効に機能します。 |
大文字と小文字が区別される演算子 | == を使用してください。 |
=~ を使用しないでください。 |
可能な場合は、大文字と小文字が区別される演算子を使用します。 |
in を使用してください。 |
in~ を使用しないでください。 |
||
contains_cs を使用してください。 |
contains を使用しないでください。 |
contains /contains_cs にはhas /has_cs を使用することをお勧めします。 |
|
検索テキスト | 特定の列を検索します。 | * を使用しないでください。 |
* によって、すべての列に対してフル テキスト検索が行われます。 |
何百万行にわたる動的オブジェクトからフィールドを抽出する | ほとんどのクエリによって、何百万行にわたる動的オブジェクトからフィールドが抽出される場合に、取り込み時に列を具体化します。 | この方法では、列の抽出に対して 1 回だけ支払います。 | |
動的オブジェクトのまれなキーおよび値の検索 | MyTable | where DynamicColumn has "Rare value" | where DynamicColumn.SomeKey == "Rare value" を使用してください。 |
MyTable | where DynamicColumn.SomeKey == "Rare value" を使用しないでください。 |
このメソッドでは、ほとんどのレコードを除外し、残りの部分でのみ JSON 解析を行います。 |
複数回使用する値を指定した let ステートメント |
materialize() 関数を使用します。 | materialize() の使用方法の詳細については、「materialize()」を参照してください。 詳細については、「名前付き式を使用するクエリを最適化する」を参照してください。 |
|
10 億を超えるレコードに型変換を適用する | 変換に取り込まれるデータ量を減らすために、クエリを再形成します。 | 避けられる場合は、大量のデータを変換しないでください。 | |
新しいクエリ | limit [small number] または count を末尾に使用します。 |
不明なデータセットに対してバインドされていないクエリを実行すると、ギガバイト単位の結果が返され、応答が遅くなり、ビジー状態になることがあります。 | |
大文字と小文字が区別されない比較 | Col =~ "lowercasestring" を使用してください。 |
tolower(Col) == "lowercasestring" を使用しないでください。 |
|
既に小文字 (または大文字) になっているデータを比較する | Col == "lowercasestring" (または Col == "UPPERCASESTRING" )。 |
大文字と小文字が区別されない比較の使用を避けてください。 | |
列のフィルター処理 | テーブル列に対してフィルター処理を行います。 | 計算列に対してフィルター処理を行わないでください。 | |
T | where predicate(*Expression*) を使用します |
T | extend _value = *Expression* | where predicate(_value) は使用しません |
||
summarize 演算子 | summarize 演算子のgroup by keys のカーディナリティが高い場合は>hint.shufflekey=<key を使用します。 |
カーディナリティが高い場合、理想的には 100 万を超えます。 | |
join 演算子 | 最初の行が最も少ないテーブル (クエリでは左端) を選択します。 | ||
1 つの列でフィルター処理するには、left semi join の代わりに in を使用します。 |
|||
クラスター間で結合する | ほとんどのデータが配置されているクラスターや Eventhouses などのリモート環境間で、結合の "右側" でクエリを実行します。 | ||
左側が小さく、右側が大きい場合の結合 | hint.strategy=broadcast を使用します。 | Small は、最大 100 メガバイト (MB) のデータを指します。 | |
右側が小さく、左側が大きい場合の結合 | join 演算子の代わりにlookup 演算子を使用します |
参照の右側が数十 MB を超える場合、クエリは失敗します。 | |
両側が大きすぎる場合の結合 | hint.shufflekey=<key>を使用します。 | 結合キーのカーディナリティが高い場合に使用します。 | |
同じ形式またはパターンを共有する文字列を含む列の値を抽出する | parse 演算子を使用します。 | 複数の extract() ステートメントを使用しないでください。 |
たとえば、 "Time = <time>, ResourceId = <resourceId>, Duration = <duration>, ...." などの値です。 |
extract() 関数 | 解析される文字列が同じ形式またはパターンに従っていない場合に、使用します。 | REGEX を使用して、必要な値を抽出します。 | |
materialize() 関数 | 具体化されたデータセットを減らし、クエリのセマンティクスを維持する可能性のあるすべての演算子をプッシュします。 | たとえば、フィルター処理するか、必要な列のみを射影します。 詳細については、「名前付き式を使用するクエリを最適化する」を参照してください。 | |
具体化されたビューを使用する | 一般的に使用される集計を格納するためには、具体化されたビューを使用します。 materialized_view() 関数を使用して、マテリアライズド パーツのみにクエリを実行することを優先します。 |
materialized_view('MV') |
処理されるデータの量を減らす
クエリのパフォーマンスは、処理する必要があるデータの量に直接依存します。 処理されるデータが少ないほど、クエリは速くなります (消費するリソースも少なくなります)。 そのため、最も重要なベスト プラクティスは、処理されるデータの量を減らすようにクエリを構成することです。
Note
次の説明では、フィルター選択性の概念を念頭に置 必要があります。 選択度は、何らかの述語でフィルター処理するときにフィルター処理されるレコードの割合です。 高度に選択的な述語は、述語を適用した後に少数のレコードのみが残ることを意味し、効果的に処理する必要があるデータの量を減らします。
重要度順:
クエリで必要なデータを持つテーブルのみを参照します。 たとえば、ワイルドカード テーブル参照で
union
演算子を使用する場合は、ワイルドカード (*
) を使用してすべてのテーブルを参照し、ソース テーブル名の述語を使用してデータをフィルター処理するのではなく、パフォーマンスの観点から少数のテーブルのみを参照することをお勧めします。クエリが特定のスコープにのみ関連する場合は、テーブルのデータ スコープを利用します。 table() 関数は、キャッシュ ポリシー (DataScope パラメーター) に従ってデータをスコープ設定することで、データを効率的に排除する方法を提供します。
テーブル参照の直後に
where
クエリ演算子を適用します。where
クエリ演算子を使用する場合、1 つのwhere
演算子を使用するか、複数の連続するwhere
演算子を使用するかに関係なく、述語を配置する順序がクエリのパフォーマンスに大きな影響を与える可能性があります。最初にシャード全体の述語を適用します。 つまり、 extent_id() 関数 および extent_tags() 関数 を使用する述語を最初に適用する必要があります。 また、特定のパーティションにデータを絞り込む選択的述語がある場合は、最初に適用する必要があります。
次に、テーブル列に作用する述語
datetime
適用します。 Kusto にはこのような列に効率的なインデックスが含まれており、多くの場合、それらのシャードにアクセスしなくてもデータ シャード全体が完全に排除されます。次に、
string
列とdynamic
列に作用する述語 、特に用語レベルで適用される述語を適用します。 選択度で述語を並べ替える。 たとえば、何百万人ものユーザーがいる場合にユーザー ID を検索することは非常に選択的であり、通常は、インデックスが非常に効率的な用語検索を伴います。次に、選択的で数値列に基づく述語を適用します。
最後に、テーブル列のデータをスキャンするクエリ (たとえば、用語がなく、インデックス作成の利点がない
contains
"@!@!"
などの述語の場合)、データの少ない列をスキャンする述語が最初になるように述語を並べ替えます。 これにより、大きな列を展開してスキャンする必要が減ります。
冗長な修飾参照の使用を避ける
テーブルや具体化されたビューなどのエンティティを名前で参照します。
たとえば、テーブル T
は、単にT
(修飾名) として参照したり、データベース修飾子 (テーブルが DB
というデータベース内にある場合にdatabase("DB").T
)、完全修飾名 (cluster("<serviceURL>").database("DB").T
など) を使用して参照したりできます。
たとえば、テーブル T
は、単にT
(修飾名) として参照したり、データベース修飾子 (テーブルが DB
というデータベース内にある場合にdatabase("DB").T
)、完全修飾名 (cluster("X.Y.kusto.windows.net").database("DB").T
など) を使用して参照したりできます。
次の理由から、名前の修飾が冗長な場合は使用しないことをお勧めします。
非修飾名は、(人間のリーダーの場合) スコープ内のデータベースに属していることを識別しやすくなります。
スコープ内データベース エンティティの参照は、常に少なくとも同じくらい高速であり、場合によっては他のデータベースに属するエンティティの方がはるかに高速です。
これは、これらのデータベースが別のクラスターにある場合に特に当てはまります。
これは、これらのデータベースが別の Eventhouse にある場合に特に当てはまります。
修飾名を避けると、読者は正しいことを行うのに役立ちます。
Note
これは、修飾名がパフォーマンスに悪いという意味を持つわけではありません。 実際、Kusto はほとんどの場合、完全修飾名がクエリのスコープ内データベースに属するエンティティを参照するタイミングを識別し、クエリを "ショートサーキット" して、クロスクラスター クエリとは見なされないようにすることができます。 ただし、不要な場合はこれに依存することはお勧めしません。
Note
これは、修飾名がパフォーマンスに悪いという意味を持つわけではありません。 実際、Kusto はほとんどの場合、完全修飾名がスコープ内データベースに属するエンティティを参照するタイミングを識別できます。 ただし、不要な場合はこれに依存することはお勧めしません。