Partage via


Optimiser les performances à l’aide de QueryExpression

Cet article décrit les méthodes permettant d’optimiser les performances lors de la récupération de données à l’aide de QueryExpression.

Modèles à éviter

La composition de requêtes optimisées pour Dataverse est essentielle pour garantir que les applications offrent une expérience rapide, réactive et fiable. Cette section décrit les modèles à éviter et les concepts à comprendre lors de la composition de requêtes pour des tables standard à l’aide du message ou des messages qui ont un paramètre qui hérite de la classe QueryBase RetrieveMultiple . ... Ces conseils s’appliquent également lors de l’envoi d’une requête sur une collection d’enregistrements à l’aide d’OData. GET Les conseils ici peuvent ne pas s’appliquer aux tableaux élastiques ou lors de l’utilisation de Dataverse Recherche.

Minimiser le nombre de colonnes sélectionnées

N’incluez pas les colonnes dont vous n’avez pas besoin dans votre requête. Les requêtes qui renvoient toutes les colonnes ou incluent un grand nombre de colonnes peuvent rencontrer des problèmes de performances en raison de la taille du jeu de données ou de la complexité de la requête.

Cette pratique est particulièrement vraie pour les colonnes logiques. Une colonne logique contient des valeurs stockées dans différentes tables de base de données. La propriété AttributeMetadata.IsLogical vous indique si une colonne est une colonne logique. Les requêtes qui contiennent de nombreuses colonnes logiques sont plus lentes car Dataverse doivent combiner les données d’autres tables de base de données.

Évitez les caractères génériques en tête dans les conditions de filtrage

Les requêtes qui utilisent des conditions avec un caractère générique Cartes au début (soit explicitement, soit implicitement avec un opérateur comme ends-with) peuvent entraîner de mauvaises performances. Dataverse ne peut pas profiter des index de base de données lors d’une requête utilisant des caractères génériques de premier plan, ce qui oblige SQL à analyser la table entière. Les analyses de table peuvent se produire même s’il existe d’autres requêtes sauvages carte non principales qui limitent l’ensemble de résultats.

L’exemple suivant est un élément de condition FetchXml qui utilise un caractère générique de début carte :

<condition attribute='accountnumber'
   operator='like'
   value='%234' />

L’exemple suivant est une QueryExpressionConditionExpression qui utilise un caractère générique de début carte :

new ConditionExpression("accountnumber", ConditionOperator.Like, "%234")

L’exemple suivant est une requête OData qui utilise un caractère générique de début carte :

$filter=startswith(accountnumber,'%234')

Lorsque le délai d’attente des requêtes expire et que ce modèle est détecté, Dataverse renvoie une erreur unique pour aider à identifier les requêtes qui utilisent ce modèle :

Nom: LeadingWildcardCauseTimeout
Code: 0x80048573
Nombre: -2147187341
Message: The database operation timed out; this may be due to a leading wildcard value being used in a filter condition. Please consider removing filter conditions on leading wildcard values, as these filter conditions are expensive and may cause timeouts.

Dataverse limite fortement les principales requêtes génériques identifiées comme un risque pour la santé de l’organisation afin d’aider à prévenir les pannes. En savoir plus sur la limitation des requêtes

Si vous utilisez des requêtes génériques de premier plan, étudiez ces options :

  • Utilisez plutôt la recherche. Dataverse
  • Modifiez votre modèle de données pour aider les gens à éviter d’avoir besoin de caractères génériques de premier plan.

Autres caractères génériques

Comme décrit dans Utiliser des caractères génériques dans les conditions pour les valeurs de chaîne, d’autres caractères au-delà du signe de pourcentage (’%’) peuvent agir comme un caractère générique. Voici deux exemples de chaînes de requête qui se comportent également comme des caractères génériques de début :

  • _234%
  • [^a]234%

Dataverse limite fortement les requêtes avec des chaînes de recherche qui commencent par ces autres caractères spéciaux génériques de premier plan.

Caractère trait d’union

Les règles de tri Unicode de classement de base de données font que certaines chaînes de recherche commençant par un tiret (« - ») fonctionnent comme des recherches génériques de premier plan. Les chaînes de recherche commençant par un trait d’union ne peuvent pas tirer parti des index de base de données si la chaîne de recherche ne contient pas de caractère non générique avant l’occurrence du caractère « % » dans la chaîne. Par exemple, -% et -%234 ne peuvent pas utiliser efficacement les index de base de données, alors que -234% le peuvent. Dataverse limite considérablement les chaînes de recherche inefficaces qui commencent par des tirets. Pour en savoir plus sur les règles de tri Unicode de classement de base de données pour les tirets, consultez Classements du serveur SQL.

Évitez d’utiliser des formules ou des colonnes calculées dans des conditions de filtre

Les valeurs des formules et des colonnes calculées sont calculées en temps réel lorsqu’elles sont récupérées. Les requêtes qui utilisent des filtres sur ces colonnes obligent Dataverse à calculer la valeur de chaque enregistrement possible pouvant être renvoyé afin que le filtre puisse être appliqué. Les requêtes sont plus lentes car Dataverse ne peut pas améliorer les performances de ces requêtes à l’aide de SQL.

Lorsque le délai d’attente des requêtes expire et que ce modèle est détecté, Dataverse renvoie une erreur unique pour aider à identifier les requêtes qui utilisent ce modèle :

Nom: ComputedColumnCauseTimeout
Code: 0x80048574
Nombre: -2147187340
Message: The database operation timed out; this may be due to a computed column being used in a filter condition. Please consider removing filter conditions on computed columns, as these filter conditions are expensive and may cause timeouts.

Pour éviter les pannes, Dataverse applique des limitations aux requêtes comportant des filtres sur les colonnes calculées identifiées comme présentant un risque pour la santé de l’environnement. En savoir plus sur la limitation des requêtes

Évitez de trier par colonnes de choix

Lorsque vous utilisez FetchXml ou QueryExpression, lorsque vous triez les résultats de la requête à l’aide d’une colonne de choix, les résultats sont triés à l’aide de l’étiquette localisée pour chaque option de choix. Trier par la valeur numérique stockée dans la base de données ne fournirait pas une bonne expérience dans votre application. Vous devez savoir que le classement des colonnes de choix nécessite davantage de ressources de calcul pour joindre et trier les lignes en fonction de la valeur d’étiquette localisée. Ce travail supplémentaire ralentit la requête. Si possible, essayez d’éviter de trier les résultats par valeurs de colonne de choix.

Note

OData est différent. Avec l’ Dataverse API Web, $orderby trie les lignes à l’aide de la valeur entière de la colonne de choix plutôt que de l’étiquette localisée.

Le classement par colonnes sur les tables associées ralentit la requête en raison de la complexité supplémentaire.

Le classement par tables associées ne doit être effectué qu’en cas de besoin, comme décrit ici :

Évitez d’utiliser des conditions sur de grandes colonnes de texte

Dataverse dispose de deux types de colonnes pouvant stocker de grandes chaînes de texte :

La limite pour ces deux colonnes est spécifiée à l’aide de la propriété MaxLength .

Vous pouvez utiliser des conditions sur des colonnes de chaîne dont un MaxLength est configuré pour moins de 850 caractères.

Toutes les colonnes de mémo ou de chaîne avec un MaxLength supérieur à 850 sont définies dans Dataverse comme de grandes colonnes de texte. Les grandes colonnes de texte sont trop volumineuses pour être indexées efficacement, ce qui entraîne de mauvaises performances lorsqu’elles sont incluses dans une condition de filtre.

Dataverse La recherche est un meilleur choix pour interroger des données dans ce type de colonnes.

Indicateurs de requête

Important

Appliquez ces options uniquement lorsqu’elles sont recommandées par le support technique Microsoft. Une utilisation incorrecte de ces options peut dégrader les performances d’une requête.

Microsoft SQL Server prend en charge plusieurs indicateurs de requête pour optimiser les requêtes. QueryExpression prend en charge les conseils de requête et peut transmettre ces options de requête au serveur SQL à l’aide de la propriété QueryExpression.QueryHints.

Option de requête Conseil SQL Server
ForceOrder Ordre de force
DisableRowGoal Indice: DISABLE_OPTIMIZER_ROWGOAL
EnableOptimizerHotfixes Indice: ENABLE_QUERY_OPTIMIZER_HOTFIXES
LoopJoin Boucle de jonction
MergeJoin Fusionner Joindre
HashJoin Jointure par hachage
NO_PERFORMANCE_SPOOL Bobine sans performances
ENABLE_HIST_AMENDMENT_FOR_ASC_KEYS Indice: ENABLE_HIST_AMENDMENT_FOR_ASC_KEYS

Plus d’informations : Astuces (Transact-SQL) - Requête

Aucun verrou

Dans les versions antérieures, la propriété QueryExpression.NoLock servait à empêcher les verrous partagés sur les enregistrements. Il n’est plus nécessaire d’inclure cette propriété

Indicateur d’union

Vous pouvez améliorer les performances lors de l’ajout d’une FilterExpression qui définit le ConditionExpression pour les colonnes de différentes tables en définissant la propriété FilterExpression.FilterHint sur union. Mais certaines restrictions s’appliquent :

  • Le FilterExpression.FilterOperator doit utiliser LogicalOperator.Or.
  • Chaque requête ne peut contenir qu’un seul indice. union
  • Si un FilterExpression avec union indice n’est pas au niveau supérieur du filtre, Dataverse transforme la requête et déplace le filtre avec un union indice vers le filtre racine.
  • Si un indice a plus de trois niveaux de profondeur, il est ignoré. union

L’exemple suivant définit un filtre avec l’ union indice sur la telephone1 colonne pour les tables compte et contact .

QueryExpression query = new("email")
{
   ColumnSet = new ColumnSet("activityid", "subject"),
   Criteria = new FilterExpression(LogicalOperator.And)
   {
      Conditions = {
         {
            new ConditionExpression(
               attributeName:"subject",
               conditionOperator:ConditionOperator.Like,
               value: "Alert:%")
         },
         {
            new ConditionExpression(
               attributeName:"statecode",
               conditionOperator:ConditionOperator.Equal,
               value: 0)
         }
      },
      Filters = {
         {
            new FilterExpression(LogicalOperator.Or){
               FilterHint = "union",
               Conditions = {
                  {
                     new ConditionExpression(
                        attributeName:"telephone1",
                        conditionOperator:ConditionOperator.Equal,
                        value: "555-123-4567"){
                           EntityName = "ac"
                        }
                  },
                  {
                     new ConditionExpression(
                        attributeName:"telephone1",
                        conditionOperator:ConditionOperator.Equal,
                        value: "555-123-4567"){
                           EntityName = "co"
                        }
                  }
               }
            }
         }
      }
   }
};        

LinkEntity linkToAccount = query.AddLink(
      linkToEntityName: "account",
      linkFromAttributeName: "regardingobjectid",
      linkToAttributeName: "accountid",
      joinOperator: JoinOperator.LeftOuter);
linkToAccount.EntityAlias = "ac";

LinkEntity linkToContact = query.AddLink(
      linkToEntityName: "contact",
      linkFromAttributeName: "regardingobjectid",
      linkToAttributeName: "contactid",
      joinOperator: JoinOperator.LeftOuter);
linkToContact.EntityAlias = "co";

Voir aussi

Interroger des données à l’aide de QueryExpression
Colonnes Sélectionner utilisant QueryExpression
Joindre des tables à l’aide de QueryExpression
Trier les lignes à l’aide de QueryExpression
Filtrer les lignes à l’aide de QueryExpression
Résultats de la page à l’aide de QueryExpression
Agréger des données à l’aide de QueryExpression
Compter les lignes à l’aide de QueryExpression