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