J'ai des tables Log et LogItem; J'écris une requête pour récupérer des données des deux. Il y en a des milliers Logs
et chacun Log
peut en avoir jusqu'à 125LogItems
La requête en question est compliquée, donc je la saute (si quelqu'un pense que c'est important, je peux probablement la poster), mais lorsque j'ai exécuté le plan SSMS Estimated Query, il m'a dit qu'un nouvel index non clusterisé améliorerait les performances jusqu'à 100%. .
Existing Index: Non-clustered
Key Colums (LogItem): ParentLogID, DateModified, Name, DatabaseModified
Query Plan Recommendation
CREATE NONCLUSTERED INDEX [LogReportIndex]
ON [dbo].[LogItem] ([ParentLogID],[DatabaseModified])
Juste pour le plaisir, j'ai créé ce nouvel index et exécuté la requête et à ma grande surprise, il faut maintenant environ 1 seconde pour que ma requête s'exécute, alors qu'elle était avant 10+ secondes.
J'ai supposé que mon index existant couvrirait cette nouvelle requête, donc ma question est pourquoi la création d'un nouvel index sur les seules colonnes utilisées dans ma nouvelle requête a-t-elle amélioré les performances? Dois-je avoir un index pour chaque combinaison unique de colonnes utilisée dans mes where
clauses?
note: Je ne pense pas que ce soit parce que SQL Server met en cache mes résultats, j'ai exécuté la requête environ 25-30 fois avant de créer l'index et cela a pris régulièrement 10-15 secondes, après l'index, il est maintenant uniformément ~ 1 ou moins.
la source
Réponses:
L'ordre des colonnes dans un index est important. Si le filtrage nécessite les colonnes 1 et 4 de l'index, l'index ne va pas aider. Il n'est utile que lors du filtrage par les N premières colonnes consécutives.
C'est parce que l'index est un arbre. Vous ne pouvez pas sélectionner efficacement tous les nœuds de l'arbre où
column3 = something
, parce qu'ils sont dispersés tous les autres, appartenant à différentes valeurs decolumn1
etcolumn2
. Mais si vous le savezcolumn1
etcolumn2
aussi, localiser la bonne branche dans l'arbre est une évidence.la source
where
s peuvent se chevaucher, vous pouvez donc avoir un index qui couvre bien plusieurswhere
s; ou vous pouvez ignorer une partie d'unewhere
clause car l'indexation sur une certaine colonne ne va pas aider de toute façon (faible sélectivité); mais en gros, oui.where
clauses n'est pas important. Le serveur les organisera toujours pour utiliser au mieux les index existants. Il s'agit seulement d'avoir un index qui inclut toutes leswhere
colonnes requises comme premières colonnes.Le bord avant d'un indice est ce qui compte.
Tant que votre requête est "couverte" par un bord d'attaque d'un index, elle sera efficace. Les index de base de données sont généralement implémentés en tant qu'arbres B et la structure de l'arbre B impose que la recherche doit être effectuée dans un certain ordre, c'est pourquoi l'ordre des champs dans l'index composite est important.
Si vous avez des "trous", par exemple si vous effectuez une recherche sur
ParentLogID
etDatabaseModified
, mais que seul l'index est activé{ParentLogID, DateModified, Name, DatabaseModified}
, alors seule la{ParentLogID}
partie de l'index peut être utilisée efficacement.(REMARQUE: certains SGBD peuvent utiliser la
{DatabaseModified}
partie via "skip scan", mais même si votre SGBD le fait, il est beaucoup moins efficace que l'accès à l'index normal) .la source
Columns (a, b, c, d, e, f)
et la plupart des requêtes sont... WHERE A IN(...) AND B = 3
mon indexIndex(a,b,c,d)
qui est bon, mais cela n'aide pas si j'ai,... WHERE A IN (...) AND D = 5
c'est pourquoi mon nouvel index que j'ai fait, aIndex(a,d)
tellement amélioré les performances, non?