7
votes

Commande d'index SQL Server (champ DateTime)

J'ai une question sur les index SQL Server. Je ne suis pas un DBA et suppose que la réponse est claire pour ceux d'entre vous qui sont. J'utilise SQL Server 2008.

J'ai une table similaire à ce qui suit (mais a plus de colonnes): xxx

Les champs importants à remarquer ici sont abondantes. , la clé primaire et la requête de la date à laquelle le résultat a été produit.

J'ai aussi l'index suivant (entre autres): xxx

dans une base de données où j'ai environ un million de lignes dans la table, l'index est utilisé lorsque vous faites une requête telle que: xxx

dans une autre instance de la même base de données, avec 50 millions de lignes, SQL Server décide de ne pas utiliser l'index comme il est plutôt groupé. Scan d'index qui finit par être horriblement lent. (et la vitesse dépend de la date). Même si j'utilise des indices de requête pour le faire utiliser IDX_Resultdate, il reste un peu lent et dépense 94% de son temps de tri par substance. Je pensais que, en créant un index avec des colonnes de personnes abondantes et de requêtes dans l'index, je pourrais accélérer ma requête.

J'ai donc créé ce qui suit: xxx

J'ai supposé qu'il utiliserait d'abord le tri par requête pour trouver les résultats correspondants, qui seraient déjà triés. par substance. Cependant, ce n'est pas le cas car cet indice ne change rien dans la performance sur l'existant.

J'ai essayé ensuite l'index suivant: xxx

Celui-ci produit le résultat prévu. Il semble revenir en temps constant (une fraction d'une seconde).

Cependant, je suis perplexe sur la raison pour laquelle IDX_ResultDate3 fonctionne bien alors que IDX_RESULTDate2 ne le fait pas.

Je supposerais qu'une recherche binaire dans la liste triée de Querytime suivie d'un premier résultat dans la liste des enfants de sa première personne est le moyen le plus rapide d'obtenir le résultat. (D'où mon ordre de tri initial).

Question latérale: Dois-je créer une colonne persistée avec la partie de date de la requête et l'index à ce sujet (j'ai déjà trois colonnes persistées comme vous pouvez le voir ci-dessus)?


0 commentaires

5 Réponses :


2
votes

Vous pouvez modifier l'index groupé en ([QueryTime], [Rulstid]) ou modifiez votre requête de

select top 1 <only the columns you actually need> from results where querytime>'2009-05-01' order by ResultID asc


2 commentaires

+1 Exactement - Tirez sur un indice de "revêtement" qui inclut tous les champs nécessaires pour satisfaire la requête (si cela est possible)


Oui, ce faisant déjà cela (pas posté ici) mais le même type de performance.



12
votes

Je suppose qu'une recherche binaire dans Comme la liste triée de la requête suivie en regardant au premier résultat dans c'est La liste des enfants des résultats est la plus rapide façon d'obtenir le résultat. (D'où mon ordre de tri initial).

Ce serait en effet rapide, mais votre requête exprime une demande différente: vous demandez le résultat avec le minimum de personnes subsidid de toutes les requêtes survenues après '2009-05-01' . Pour satisfaire la demande, il doit rechercher au début de la gamme ('2009-05-01'), démarrez une analyse à partir de cette position pour extraire tous les subventionnels, triez-les, puis renvoyez le top 1 (le résultat minimum). Le deuxième index que vous avez ajouté [idx_resultdate2] n'aide pas beaucoup non plus. La requête doit faire à peu près exactement la même recherche et numériser: les résultats sont triés whithin une date de résultat , afin de trouver le sommet résultant de tous les résultats tous suivants '2009-05-01' La requête doit toujours scanner l'index jusqu'à la fin.

sur votre dernier index, [idx_resultdate3], la requête est triche. Ce qu'il fait commence une analyse sur l'INDE et de regarder la valeur de la requête, sachant que dans cet indice scanner le résultat premier qui a une requête dans la plage souhaitée (> '2009-05-01 ') Est-ce celui que vous voulez (car le résultat est garanti d'être le top 1). Vous obtenez le résultat dans une «fraction d'une seconde» de la chance pure: vous avez un résultat correspondant au début de l'index. La requête peut bien scanner l'intégralité de l'index et correspondre au résultat très lat. Vous pouvez insérer un nouveau résultat avec une requête comme '2010-01-01', puis la chercher, vous verrez que la performance se dégrade que la requête doit scanner l'intégralité de l'index jusqu'à la fin (toujours plus rapide qu'une analyse de table car de la taille d'index plus étroite).

Ma question est la suivante: Êtes-vous absolument certain que votre requête doit renvoyer le top 1 en ordre par des personnes abondantes? Ou vous venez de choisir la commande par arbitrairement? Si vous pouvez modifier la commande à la demande de requête, dites, requête, puis l'un de l'index ( mis à jour : avec la requête en tant que colonne la plus à gauche) retournera une simple recherche et une fermeture, pas de scansn et pas de tri. < / p>


1 commentaires

Très bonne explication. Je comprends maintenant. Je verrai si je peux ré-ingénieur l'application pour utiliser le tri de la requête.



4
votes

Vous avez une condition de filtrage distangée sur un champ avec par un autre champ.

Un index, même un indice composite, ne peut pas être utilisé pour servir les deux conditions dans ce cas.

Lorsque vous créez un index sur (Querytime, résultatd) , l'index est utilisé pour le filtrage. Le moteur doit toujours commander les Resultset.

Lorsque vous créez un index sur (résultatd, question) , l'index est utilisé pour la commande.

Etant donné que vous avez besoin d'un Top 1 Résultat et la ligne qui se sait que ce résultat se produit au début de l'index, cette dernière approche s'avère performante.

Si votre condition de filtrage serait sélective (c'est-à-dire que cela reviendrait peu de lignes) et le premier résultat dont vous avez besoin devrait être à la fin de l'index, la première approchearch serait meilleure.

Voir cet article dans mon blog pour quelques explications et astuces sur l'index à créer dans lesquelles conditions:


0 commentaires

0
votes

La première chose que je suggérerais, c'est de vérifier si les statistiques de ce tableau (tous les index) sont à jour.

Étant donné que vous obtenez deux plans d'exécution différents avec différents ensembles de données, il semble que SQL Server faite un "appel de jugement" infâme dans la sélection d'un plan d'exécution sur un autre.

Je suis d'accord avec l'explication de Remus de la raison pour laquelle vous obtenez des résultats "magiques" avec votre dernier index.

Sa suggestion est aussi bonne - voulez-vous vraiment commander par substantid? Ou si vous pouvez commander par QueryTime, vous aurez beaucoup de meilleures performances car le plan d'exécution sera en mesure d'utiliser la commande d'index comme ordre de jeu de résultats (et il cherchera via l'index, contre la numérisation).


1 commentaires

Oui, les statistiques sont à jour. (Et oui, il doit être trié ... malheureusement!)



0
votes

Je ne suis pas sûr que je puisse répondre à la question, mais soulignerait que la clé d'index en cluster est déjà incluse dans tout autre indice, c'est donc redondant d'inclure le résultat dans l'un des autres index que vous proposez. < / p>


0 commentaires