Meilleures pratiques pour les requêtes Langage de requête Kusto

Voici plusieurs meilleures pratiques à suivre pour accélérer l’exécution de votre requête.

En bref

Action Utilisation N’utilisez pas Notes
Réduire la quantité de données interrogées Utilisez des mécanismes tels que l’opérateur where pour réduire la quantité de données en cours de traitement. Consultez ci-dessous pour connaître les moyens efficaces de réduire la quantité de données en cours de traitement.
Éviter d’utiliser des références qualifiées redondantes Lorsque vous référencez des entités locales, utilisez le nom non qualifié. Pour plus d’informations sur le sujet, voir ci-dessous.
datetime Colonnes Utilisez le type de données datetime. N’utilisez pas le type de long données. Dans les requêtes, n’utilisez pas de fonctions de conversion de temps Unix, telles que unixtime_milliseconds_todatetime(). Utilisez plutôt des stratégies de mise à jour pour convertir l’heure unix en type de données pendant l’ingestion datetime .
Opérateurs de chaîne Utilisez l’opérateur has N’utilisez pas contains Lorsque vous recherchez des jetons complets, has fonctionne mieux, car il ne recherche pas de sous-chaînes.
Opérateurs respectant la casse Utilisez ==. N’utilisez pas =~ Utilisez des opérateurs respectant la casse quand c’est possible.
Utilisez in. N’utilisez pas in~
Utilisez contains_cs. N’utilisez pas contains Si vous pouvez utiliser has/has_cs et n’utilisez pas contains/contains_cs, c’est encore mieux.
Recherche de texte Recherchez dans une colonne spécifique N’utilisez pas * * effectue une recherche en texte intégral dans toutes les colonnes.
Extraire les champs d’objets dynamiques dans plusieurs millions de lignes Matérialisez votre colonne au moment de l’ingestion si la plupart de vos requêtes extraient des champs d’objets dynamiques dans des millions de lignes. De cette façon, vous ne payez qu’une seule fois pour l’extraction de colonne.
Rechercher les clés/valeurs rares dans des objets dynamiques Utilisez MyTable | where DynamicColumn has "Rare value" | where DynamicColumn.SomeKey == "Rare value". N’utilisez pas MyTable | where DynamicColumn.SomeKey == "Rare value" De cette façon, vous filtrez la plupart des enregistrements et vous effectuez l’analyse JSON seulement pour le reste.
Instruction let avec une valeur que vous utilisez plusieurs fois Utiliser la fonction materialize() Pour plus d’informations sur l’utilisation de la fonction materialize(), consultez materialize(). Pour plus d’informations, consultez Optimiser les requêtes qui utilisent des expressions nommées.
Appliquer des conversions sur plus de 1 milliard d’enregistrements Remodelez votre requête pour réduire la quantité de données chargées dans la conversion. Ne convertissez pas de grandes quantités de données si vous pouvez l’éviter.
Nouvelles requêtes Utilisez limit [small number] ou count à la fin. L’exécution de requêtes indépendantes sur des jeux de données inconnus peut générer des Go de résultats à retourner au client, ce qui entraîne une réponse lente et un cluster occupé.
Comparaisons ne respectant pas la casse Utilisez Col =~ "lowercasestring". N’utilisez pas tolower(Col) == "lowercasestring"
Comparer des données déjà en minuscules (ou en majuscules) Col == "lowercasestring" (ou Col == "UPPERCASESTRING") Évitez d’utiliser des comparaisons ne respectant pas la casse.
Filtrage sur les colonnes Filtrez sur une colonne de table. Ne filtrez pas sur une colonne calculée.
Utilisez T | where predicate(*Expression*). N’utilisez pas T | extend _value = *Expression* | where predicate(_value)
opérateur summarize Utilisez hint.shufflekey=<key> lorsque les group by keys de l’opérateur summarize ont une cardinalité élevée. Une cardinalité élevée est idéalement supérieure à 1 million.
opérateur join Sélectionnez la table contenant moins de lignes comme première table (la plus à gauche dans la requête).
Utilisez in au lieu de semi join gauche pour filtrer par une seule colonne.
Jointure entre clusters Entre clusters, exécutez la requête sur le côté « droit » de la jointure, où se trouvent la plupart des données.
Joindre quand le côté gauche est petit et le côté droit est grand Utilisez hint.strategy=broadcast Small fait référence à jusqu’à 100 Mo de données.
Joindre lorsque le côté droit est petit et que le côté gauche est grand Utiliser l’opérateur de recherche au lieu de l’opérateur join Si le côté droit de la recherche est supérieur à plusieurs dizaines de Mo, la requête échoue.
Joindre quand les deux côtés sont trop grands Utiliser hint.shufflekey=<key> Utilisez lorsque la clé de jointure présente une cardinalité élevée.
Extraire des valeurs d’une colonne contenant des chaînes partageant les mêmes format ou modèle Utilisez l’opérateur parse N’utilisez pas plusieurs instructions extract(). Par exemple, des valeurs telles que "Time = <time>, ResourceId = <resourceId>, Duration = <duration>, ...."
Fonction extract() Utilisez-la lorsque les chaînes analysées ne suivent pas toutes les mêmes format ou modèle. Extrayez les valeurs requises à l’aide d’une expression régulière.
Fonction materialize() Envoyez (push) tous les opérateurs possibles qui réduisent le jeu de données matérialisé tout en conservant la sémantique de la requête. Par exemple, filtrez, ou projetez uniquement les colonnes requises. Pour plus d’informations, consultez Optimiser les requêtes qui utilisent des expressions nommées.
Utiliser des vues matérialisées Utilisez des vues matérialisées pour stocker les agrégations couramment utilisées. Préférer utiliser la materialized_view() fonction pour interroger uniquement la partie matérialisée materialized_view('MV')

Réduire la quantité de données en cours de traitement

Les performances d’une requête dépendent directement de la quantité de données qu’elle doit traiter. Moins les données sont traitées, plus la requête est rapide (et moins elle consomme de ressources). Par conséquent, la meilleure pratique la plus importante consiste à structurer la requête de manière à réduire la quantité de données traitées.

Notes

Dans la discussion ci-dessous, il est important d’avoir à l’esprit le concept de sélectivité des filtres. La sélectivité est le pourcentage des enregistrements qui sont filtrés lors du filtrage par un prédicat. Un prédicat hautement sélectif signifie qu’il ne reste qu’une poignée d’enregistrements après l’application du prédicat, ce qui réduit la quantité de données qui doivent ensuite être traitées efficacement.

Par ordre d’importance :

  • Seules les tables de référence dont les données sont nécessaires à la requête. Par exemple, lors de l’utilisation de l’opérateur union avec des références de table générique, il est préférable, à partir d’un point de vue de performances, de ne référencer qu’une poignée de tables, au lieu d’utiliser un caractère générique (*) pour référencer toutes les tables, puis filtrer les données à l’aide d’un prédicat sur le nom de la table source.

  • Tirez parti de l’étendue des données d’une table si la requête n’est pertinente que pour une étendue spécifique. La fonction table() fournit un moyen efficace d’éliminer les données en les définissant en fonction de la stratégie de mise en cache (paramètre DataScope ).

  • Appliquez l’opérateur where de requête immédiatement après les références de table.

  • Lors de l’utilisation de l’opérateur where de requête, une utilisation judicieuse de l’ordre des prédicats (dans un opérateur unique ou avec un certain nombre d’opérateurs consécutifs, peu importe lequel) peut avoir un effet significatif sur les performances de la requête, comme expliqué ci-dessous.

  • Appliquez d’abord des prédicats de partition entière. Cela signifie que les prédicats qui utilisent la fonction extent_id() doivent être appliqués en premier, tout comme les prédicats qui utilisent la fonction extent_tags() et les prédicats qui sont très sélectifs sur les partitions de données de la table (si définis).

  • Ensuite, appliquez des prédicats qui agissent sur les colonnes de datetime table. Kusto inclut un index très efficace sur ces colonnes, éliminant souvent complètement les partitions de données entières sans avoir à accéder à ces partitions.

  • Ensuite, appliquez les prédicats qui agissent sur string et dynamic les colonnes, en particulier les prédicats qui s’appliquent au niveau du terme. Les prédicats doivent être triés en fonction de la sélectivité (par exemple, la recherche d’un ID utilisateur quand il y a des millions d’utilisateurs est très sélective et est généralement une recherche de terme pour laquelle l’index est très efficace).)

  • Ensuite, appliquez des prédicats sélectifs basés sur des colonnes numériques.

  • Enfin, pour les requêtes qui analysent les données d’une colonne de table (par exemple, pour les prédicats tels que « contient » @ !@ ! » qui n’ont aucun terme et ne bénéficient pas de l’indexation), triez les prédicats de sorte que ceux qui analysent les colonnes avec moins de données soient les premiers. Cela réduit la nécessité de décompresser et d’analyser de grandes colonnes.

Éviter d’utiliser des références qualifiées redondantes

Les entités telles que les tables et les vues matérialisées sont référencées par nom. Par exemple, la table T peut être référencée simplement T (nom non qualifié ), ou en utilisant un qualificateur de base de données (par exemple database("DB").T , lorsque la table se trouve dans une base de données appelée DB), ou en utilisant un nom complet (par exemple cluster("X.Y.kusto.windows.net").database("DB").T).

Il est recommandé d’éviter d’utiliser des qualifications de nom lorsqu’elles sont redondantes, pour les raisons suivantes :

  1. Les noms non qualifiés sont plus faciles à identifier (pour un lecteur humain) comme appartenant à la base de données dans l’étendue.

  2. Le référencement des entités de base de données dans l’étendue est toujours au moins aussi rapide, et dans certains cas beaucoup plus rapide, que les entités qui appartiennent à d’autres bases de données (en particulier lorsque ces bases de données se trouvent dans un autre cluster.) Éviter les noms qualifiés aide le lecteur à faire la bonne chose.

Notes

Cela ne veut pas dire que les noms qualifiés sont mauvais pour les performances. En fait, Kusto est en mesure dans la plupart des cas d’identifier quand un nom complet fait référence à une entité appartenant à la base de données dans l’étendue et de « court-circuiter » la requête afin qu’elle ne soit pas considérée comme une requête inter-cluster. Toutefois, nous vous recommandons de ne pas vous appuyer sur cela lorsque cela n’est pas nécessaire, pour les raisons spécifiées ci-dessus.