web-dev-qa-db-fra.com

Ordre de traitement SQL Server Join / where

Après avoir lu requête SQL lente, je ne sais pas comment l'optimiser , cela m'a fait réfléchir sur les performances générales des requêtes. Certes, nous avons besoin que les résultats de la première table (lorsque d'autres tables sont jointes) soient aussi petits que possible avant de se joindre (jointures internes pour cette question) afin de rendre nos requêtes un tout petit peu plus rapides.

Exemple, devrait-il:

SELECT *
FROM   ( SELECT * FROM table1 WHERE col = @val ) t
INNER JOIN table2 ON col = col2

Soyez meilleur/plus rapide que:

SELECT *
FROM table1
INNER JOIN table2 ON col = col2
WHERE table1.col = @val

Ma théorie est la suivante (ce n'est peut-être pas la bonne mise en œuvre, j'essaie de me souvenir d'un livre interne de SQL Server 2008 que j'ai lu (MSFT Press)):

  1. Le processeur de requêtes obtient d'abord la table de gauche (table1)
  2. Joint la deuxième table (table2) et forme un produit cartésien avant de filtrer les lignes nécessaires (le cas échéant)
  3. Exécute ensuite les clauses WHERE, ORDER BY, GROUP BY, HAVING avec la dernière instruction SEELCT.

Donc, si dans l'instruction # 1 ci-dessus, la table est plus petite, le moteur SQL a moins de travail à faire lors de la formation des produits cartésiens. Ensuite, lorsque vous atteignez l'instruction where, vous disposez d'un jeu de résultats réduit à partir duquel filtrer en mémoire.

Je pourrais être si loin du but que c'est irréel. Comme je l'ai dit, c'est une théorie.

Tes pensées?

Remarque : Je viens juste de penser à cette question et je n'ai pas encore eu l'occasion de faire des tests moi-même.

Note 2 : Tagué comme SQL Server car je ne sais pas n'importe quoi à propos de l'implémentation de MySql etc. libre de répondre/commenter quand même

18
Stuart Blackler

Le traitement logique d'une requête est activé MSDN (écrit par l'équipe Microsoft SQL Server, pas par des tiers)

1. FROM
2. ON
3. JOIN
4. WHERE
5. GROUP BY
6. WITH CUBE or WITH ROLLUP
7. HAVING
8. SELECT
9. DISTINCT
10. ORDER BY
11. TOP

Une table dérivée suit cela, puis la requête externe recommence etc etc

C'est logique cependant: pas réel . Peu importe comment SQL Server le fait, ces sémantiques sont respectées à la lettre. Le "réel" est déterminé par l'Optimiseur de Requête (QO) et vous évitez le produit Cartesion intermédiaire que vous avez mentionné.

Il convient de mentionner que SQL est déclaratif: vous dites "quoi" pas "comment" comme vous le feriez pour une programmation procédurale/impérative (Java, .net). Donc, dire "cela se produit avant cela" est faux dans de nombreux cas (par exemple, supposition de courts-circuits ou ordre de L à R O WH)

Dans votre cas ci-dessus, le QO générera le même plan, quelle que soit sa structure, car il s'agit d'une simple requête.

Cependant, le QO est basé sur les coûts et pour une requête complexe, il peut prendre 2 semaines pour générer le plan idéal. Il fait donc "assez bien", ce qui n'est pas le cas.

Ainsi, votre premier cas peut aider l'optimiseur à trouver un meilleur plan car l'ordre de traitement logique est différent pour les 2 requêtes. Mais ce n'est peut-être pas le cas.

J'ai utilisé cette astuce sur SQL Server 2000 pour obtenir une amélioration des performances de vitesse 60x sur les requêtes de rapports. Au fur et à mesure que le QO améliore la version en version, il améliore ces choses.

Et le livre que vous avez mentionné: il y a un différend à ce sujet
Voir SO et les liens suivants: https://stackoverflow.com/q/3270338/27535

16
gbn

Une requête SQL n'est pas de nature procédurale, il n'y a pas de traitement de haut en bas des opérateurs de jointure. L'ordre des tables dans vos exemples de requêtes n'a aucune influence sur le plan d'exécution car ils sont logiquement équivalents et généreront exactement le même plan.

Vous avez en quelque sorte évalué deux des options que optimiseur de requête pourrait considérer lors de la génération d'un plan pour cette requête. Le principal facteur qui influence le choix du plan est le statistiques pour les tables impliquées et les coûts associés aux choix de l'opérateur dans tous les plans candidats.

Une jointure à deux tables très simple, comme votre exemple, peut être satisfaite par l'un des centaines de plans d'exécution différents. L'optimiseur décide quelle sera la meilleure façon de répondre à votre requête en comparant les coûts de ces plans.

Il se trompe parfois et vous pouvez l'aider à faire de meilleurs choix grâce à une indexation améliorée, à la mise à jour des statistiques et à l'application d'indices. Dans de très rares cas, vous souhaiterez peut-être forcer l'ordre d'exécution en utilisant l'indicateur FORCE ORDER, mais cela doit être utilisé avec parcimonie. C'est un marteau pour casser un écrou, l'optimiseur peut généralement être incité à générer de meilleurs plans en lui fournissant de meilleures informations.

6
Mark Storey-Smith