Il s'agit d'une simple sélection dans une table temporaire, reliant à gauche une table existante sur sa clé primaire, avec deux sous-sélections utilisant le top 1 faisant référence à la table jointe.
Dans du code:
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND
TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
JoinedTable.WhereColumn IN (1, 3)
Ceci est une réplique exacte de ma requête.
Si je supprime les deux sous-sélections, cela fonctionne très bien et rapidement. Avec les deux sous-sélections, j'obtiens environ 100 enregistrements par seconde, ce qui est extrêmement lent pour cette requête car elle devrait renvoyer près d'un million d'enregistrements.
J'ai vérifié si chaque table a une clé primaire, elles le font toutes. Ils ont tous des index et des statistiques pour leurs colonnes importantes, comme ceux de ces clauses WHERE et ceux de la clause JOIN. La seule table sans clé primaire définie ni index est la table temporaire, mais ce n'est pas le problème non plus car ce n'est pas celle liée aux sous-sélections lentes, et comme je l'ai mentionné, sans sous-sélection, elle fonctionne très bien.
Sans ceux- TOP 1
ci, il renvoie plus d'un résultat et génère une erreur.
De l'aide, quelqu'un?
MODIFIER :
Le plan d'exécution m'a donc dit qu'il me manquait un index. Je l'ai créé et recréé certains des autres index. Après un certain temps, le plan d'exécution les utilisait et la requête s'exécute désormais rapidement. Le seul problème est que je ne réussis pas à recommencer sur un autre serveur, pour la même requête. Donc, ma solution sera d'indiquer quel index SQL Server utilisera.
Réponses:
Je pense que dans une requête d'un million d'enregistrements, vous devez éviter des choses comme
OUTER JOINS
. Je vous suggère d'utiliserUNION ALL
Au lieu deLEFT JOIN
. Tant que je pense queCROSS APPLY
c'est plus efficace que la sous-requête dans la clause select, je modifierai la requête écrite par Conard Frix, qui je pense est correcte.maintenant: quand j'ai commencé à modifier votre requête , j'ai remarqué que vous avez une clause WHERE disant:
JoinedTable.WhereColumn IN (1, 3)
. dans ce cas, si le champ est nul, la condition devient fausse. alors pourquoi utilisez-vous LEFT JOIN pendant que vous filtrez des lignes de valeur nulle? Il suffit de remplacerLEFT JOIN
AvecINNER JOIN
, je vous garantis que ce sera plus rapide.à propos d'INDEX:
veuillez noter que lorsque vous avez un index sur une table, dites
et votre index est:
et vous voulez faire quelque chose comme ça:
dans votre index, vous n'avez pas inclus la colonne
b
alors que se passe-t-il?si sql-server utilise votre index, il devra chercher dans l'index, appelé "Index Seek" puis se référer à la table principale pour obtenir la colonne
b
, appelée "Look Up" . Cette procédure peut prendre beaucoup plus de temps que l'analyse de la table elle-même: "Analyse de table" .mais sur la base des statistiques dont dispose sql-server, dans de telles situations, il se peut qu'il n'utilise pas du tout votre index.
vérifiez donc tout d'abord
Execution Plan
si l'index est utilisé.si oui ou non les deux, modifiez votre index pour inclure toutes les colonnes que vous sélectionnez. dire comme:
dans ce cas, la recherche ne sera pas nécessaire et votre requête s'exécutera beaucoup plus rapidement.
la source
C'est le sous-sélection dans votre sélection de colonne qui provoque le retour lent. Vous devriez essayer d'utiliser vos sous-sélections dans les jointures de gauche, ou utiliser une table dérivée comme je l'ai défini ci-dessous.
Utilisation des jointures gauches à deux instances de la troisième table
Utilisation d'une table dérivée
la source
Essayez plutôt une application croisée
Vous pouvez également utiliser les CTE et row_number ou une requête en ligne à l'aide de MIN
la source
Déplacez les bits JOIN hors de la partie principale de la clause et placez-les en tant que sous-sélection. Le déplacer vers la section WHERE et JOIN vous garantit que vous n'avez pas à sélectionner TOP 1 encore et encore, ce qui, je pense, est la raison de sa lenteur. Si vous souhaitez vérifier cela, examinez le plan d'exécution.
la source
Les
ThirdTable
références (sous-sélections dans votre exemple) nécessitent la même attention d'index que toute autre partie d'une requête.Peu importe si vous utilisez des sous-sélections:
JOINT GAUCHE (tel que proposé par John Hartsock):
APPLICATION CROISÉE (comme proposé par Conrad Frix):
Vous devez vous assurer qu'ils
covering indexes
sont définis pourThirdTable.SomeColumn
etThirdTable.SomeOtherColumn
et que les index sont uniques. Cela signifie que vous devrez qualifier davantage lesThirdTable
références pour éliminer la sélection de plusieurs lignes et améliorer les performances. Le choix desub selects
,LEFT JOIN
ouCROSS APPLY
n'aura pas vraiment d'importance jusqu'à ce que vous amélioriez la sélectivité pourThirdTable.SomeColumn
etThirdTable.SomeOtherColumn
en incluant plus de colonnes pour garantir une sélectivité unique. D'ici là, je m'attends à ce que vos performances continuent de souffrir.Le
covering index
sujet est joliment présenté par Maziar Taheri; sans répéter son travail, j'insiste sur la nécessité de prendre à cœur l'utilisation des index de recouvrement.En bref: améliorez la sélectivité pour les requêtes
ThirdTable.SomeColumn
etThirdTable.SomeOtherColumn
(ou jointures) en ajoutant des colonnes dans la table associées pour garantir une correspondance de ligne unique. Si cela n'est pas possible, vous continuerez à souffrir de problèmes de performances car le moteur est occupé à tirer des rangées qui sont ensuite jetées. Cela a un impact sur vos E / S, votre processeur et, en fin de compte, sur le plan d'exécution.la source