Nous exécutons un site Web qui a 250MM de lignes dans une table et dans une autre table à laquelle nous le joignons pour la plupart des requêtes a un peu moins de 15MM de lignes.
Exemples de structures:
MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows
Nous devons régulièrement faire quelques requêtes sur toutes ces tables. L'une consiste à saisir des statistiques pour les utilisateurs gratuits (~ 10 000 utilisateurs gratuits).
Select Count(1) from DetailsTable dt
join MasterTable mt on mt.Id = dt.MasterId
join UserTable ut on ut.Id = mt.UserId
where ut.Role is null and mt.created between @date1 and @date2
Le problème est que cette requête s'exécutera parfois très longtemps en raison du fait que les jointures se produisent bien avant le où.
Dans ce cas, serait-il plus judicieux d'utiliser où au lieu de jointures ou éventuellement where column in(...)
?
join
best-practices
Jeremy Boyd
la source
la source
Réponses:
Pour les SGBDR modernes, il n'y a pas de différence entre "JOIN explicite" et "JOIN-in-the-WHERE" (si tous les JOINS sont INNER) en ce qui concerne les performances et le plan de requête.
La syntaxe JOIN explicite est plus claire et moins ambiguë (voir les liens ci-dessous)
Maintenant, le JOIN-before-WHERE est un traitement logique et non un traitement réel et les optimiseurs modernes sont assez intelligents pour le réaliser.
Votre problème ici est probablement l'indexation.
Veuillez nous montrer tous les index et clés de ces tables. Et les plans de requête
Remarque: cette question aurait été proche sur StackOverflow pour être un doublon maintenant ... COUNT (1) vs COUNT (*) est un autre mythe éclaté aussi.
la source
join
etwhere
clause. J'optimise en permanence les requêtes longues et parfois les requêtes utilisant lawhere
clause fonctionnent mieux que celles utilisantjoin
un facteur jusqu'à 70x. Si c'était aussi simple et direct, la vie serait constituée d'arcs-en-ciel et de licornes. Et il ne s'agit pas d'un ancien moteur obscur - en ce moment, je regarde 70x l'avantage de lawhere
clause dans SQL 2012.where
requête de clause s'exécute dans le grand lot dont elle est censée faire partie, elle surpasse lajoin
requête d'une énorme marge. Les requêtes SQL ne s'exécutent pas dans le vide - elles sont affectées par le reste de la charge utile du serveur, et souvent leswhere
requêtes de clause s'en sortent assez bien, ce qui est gênant car lajoin
syntaxe est en effet beaucoup plus propre.Vous devez refactoriser complètement la requête
Essayez d'exécuter les clauses WHERE plus tôt et les JOIN plus tard
Même si vous exécutez un plan EXPLAIN sur cette requête refactorisée et qu'elle semble pire que votre version d'origine, essayez-la quand même. Les tables temporaires créées en interne effectueront des jointures cartésiennes, mais ces tables sont plus petites pour fonctionner.
J'ai eu cette idée dans cette vidéo YouTube .
J'ai essayé les principes de la vidéo dans une question très complexe dans StackOverflow et j'ai obtenu une prime de 200 points.
@gbn a mentionné avoir vérifié que les bons index étaient en place. Dans ce cas, veuillez indexer la colonne créée dans MasterTable.
Essaie !!!
MISE À JOUR 2011-06-24 22:31 EDT
Vous devez exécuter ces requêtes:
Si NullRoles X 20 <AllRoles (en d'autres termes, si NullRoles est inférieur à 5% des lignes du tableau), vous devez créer un index non unique du rôle dans UserTable. Sinon, une table complète de UserTable suffirait car l'Optimiseur de requête peut éventuellement exclure l'utilisation d'un index.
MISE À JOUR 2011-06-25 12:40 EDT
Étant donné que je suis un administrateur de base de données MySQL, ma méthode de travail nécessite de ne pas faire confiance à MySQL Query Optimizer par un pessimisme positif et d'être conservateur. Ainsi, j'essaierai de refactoriser une requête ou de créer les index de couverture nécessaires pour devancer les mauvaises habitudes cachées de MySQL Query Optimizer. La réponse de @ gbn semble plus complète dans la mesure où SQL Server peut avoir plus de "bon sens" évaluant les requêtes.
la source
Nous avions un tableau [Détail] d'environ 75 millions de lignes; une table [Master] d'environ 400K lignes et une table [Item] associée qui avait 7 lignes - toujours et pour toujours. Il stockait le petit ensemble de «numéros d'article» (1-7) et modélisait un formulaire papier, dont des millions étaient imprimés et distribués chaque mois. La requête la plus rapide était celle à laquelle vous pensiez le moins probablement en premier, impliquant l'utilisation d'une jointure cartésienne. IIRC, c'était quelque chose comme:
Même s'il existe un lien «id» logique entre [Item] et [Detail], CROSS JOIN a mieux fonctionné qu'INNER JOIN.
Le RDBMS était Teradata avec sa technologie MPP, et IDR quel était le schéma d'indexation. La table à 7 lignes n'avait pas d'index, car SCAN DES TABLEAUX donnait toujours les meilleurs résultats.
la source