SQL Server les performances de la requête - la suppression besoin de Hash Match (Inner Join)
J'ai la requête suivante, qui fait très peu et est un exemple du type de joint que je fais à travers tout le système.
select t1.PrimaryKeyId, t1.AdditionalColumnId
from TableOne t1
join TableTwo t2 on t1.ForeignKeyId = t2.PrimaryKeyId
join TableThree t3 on t1.PrimaryKeyId = t3.ForeignKeyId
join TableFour t4 on t3.ForeignKeyId = t4.PrimaryKeyId
join TableFive t5 on t4.ForeignKeyId = t5.PrimaryKeyId
where
t1.StatusId = 1
and t5.TypeId = 68
Il existe des index sur toutes les colonnes de jointure, cependant, le rendement n'est pas grande. L'inspection du plan de requête révèle beaucoup de Hash Match (Jointures internes) quand vraiment je veux voir les jointures de Boucle Imbriquée.
Le nombre d'enregistrements dans chaque tableau est comme suit:
select count(*) from TableOne
= 64393
select count(*) from TableTwo
= 87245
select count(*) from TableThree
= 97141
select count(*) from TableFour
= 116480
select count(*) from TableFive
= 62
Quelle est la meilleure façon d'améliorer les performances de ce type de requête?
- Avez-vous testé les performances à l'aide de jointures de boucle pour vérifier qu'il est une amélioration?
- Devrait TableThree être l'alias t3? Et de le REJOINDRE pour TableThree, TableFour alors?
- non, je n'ai pas, c'est une présomption actuellement. Je ne m'attends pas à cette requête de prendre du temps pour s'exécuter.
- SQL Server intéresse aussi à la cardinalité lors du choix d'adhérer à la méthode. Vous pouvez essayer de
OPTION (LOOP JOIN)
et regarder le plan et la performance. - oui, désolé, c'est corrigé.
- peel: Est TableFour t4 sur
t2.ForeignKeyId = t4.PrimaryKeyId
bon maintenant? EtTableThree t3 on t1.PrimaryKeyId = t3.ForeignKeyId
? - oui c'est bon maintenant.
Vous devez vous connecter pour publier un commentaire.
Premières pensées:
Je ne voudrais pas vous soucier de votre méthode join encore...
Personnellement, je n'ai jamais utilisé un indicateur de JOINTURE. Ils ne fonctionnent que pour les données, les index et les statistiques que vous avez à ce point dans le temps. Comme ces changements, votre indicateur de JOINTURE limites de l'utilisation de l'optimiseur de
Index pour tableOne.. un de
(Status, ForeignKeyId) INCLUDE (AdditionalColumnId)
(ForeignKeyId, Status) INCLUDE (AdditionalColumnId)
Index pour tableFive... probablement
(typeID, PrimaryKeyId)
Edit: mis à jour le REJOINT et EXISTE pour correspondre à la question des correctifs
Exists
donne SQL Server information supplémentaire: il peut arrêter après le premier match, contrairement àjoin
, où il dispose d'une boucle sur tous les matches. Pour des raisons de cohérence, peut-être remplacer le joint surt4
ett5
avecexists
trop. +1...EXISTS (T3 EXISTS (T4 EXISTS (T5)))
SQL Server est très bon à l'optimisation des requêtes, mais c'est également conservateur: il optimise les requêtes pour le pire des cas. Une jointure de boucle en général, les résultats dans une recherche d'index et une recherche de signet pour chaque ligne. Parce que la boucle se joint à la cause dramatique dégradation pour les grands ensembles, SQL Server hésite à les utiliser, à moins d'être certain sur le nombre de lignes.
Vous pouvez utiliser le
forceseek
indicateur de requête à la force d'un index de recherche:Alternativement, vous pouvez forcer une jointure de boucle avec le
loop
mot-clé:Indicateurs de requête, à la limite de SQL Server de la liberté, de sorte qu'il ne peut plus s'adapter à des changements de circonstances. C'est la meilleure pratique pour éviter les indicateurs de requête, à moins qu'il existe un besoin d'entreprise qui ne peuvent être satisfaits sans eux.
select @var1 = t1.PrimaryKeyId, @var2 = t1.AdditionalColumnId
de prendre cela en compte lors de la comparaison des performances. Il me semble qu'il coûte à la jointure interne comme étant plus cher que ce qu'il fait est-ce alors? Des statistiques à jour sur toutes les tables?