Je compare deux requêtes dans SQL Server 2012. Le but est d'utiliser toutes les informations pertinentes disponibles à partir de l'optimiseur de requêtes lors du choix de la meilleure requête. Les deux requêtes produisent les mêmes résultats; le orderid maximum pour tous les clients.
L'effacement du pool de mémoire tampon a été effectué avant d'exécuter chaque requête avec FREEPROCCACHE et DROPCLEANBUFFERS
En utilisant les informations fournies ci-dessous, quelle requête est le meilleur choix?
-- Query 1 - return the maximum order id for a customer
SELECT orderid, custid
FROM Sales.Orders AS O1
WHERE orderid = (SELECT MAX(O2.orderid)
FROM Sales.Orders AS O2
WHERE O2.custid = O1.custid);
-- Query 2 - return the maximum order id for a customer
SELECT MAX(orderid), custid
FROM Sales.Orders AS O1
group by custid
order by custid
TEMPS STATISTIQUE
Requête 1 TEMPS STATISTIQUE: Temps CPU = 0 ms, temps écoulé = 24 ms
Requête 2 TEMPS STATISTIQUE: Temps CPU = 0 ms, temps écoulé = 23 ms
STATISTIQUES IO
Requête 1 STATISTIQUES IO: Table 'Commandes'. Nombre de balayages 1, lectures logiques 5, lectures physiques 2, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.
Requête 2 STATISTIQUES IO: Table 'Commandes'. Nombre de balayages 1, lectures logiques 4, lectures physiques 1, lectures anticipées 8, lob lectures logiques 0, lob physiques lectures 0, lob lectures anticipées lisent 0.
Plans d'exécution
SELECT propriétés Query 1
SELECT propriétés Requête 2
Conclusions:
Requête 1
- Coût par lot de 48%
- Lectures logiques 5
- Lectures physiques 2
- Lectures anticipées: 0
- Temps CPU: 0 ms
- Temps écoulé 24 ms
- Coût estimé du sous-arbre: 0,0050276
- CompileCPU: 2
- CompileMemory: 384
- CompileTime: 2
Requête 2
- Coût par lot 52%
- Lectures logiques 4
- Physcial lit 1
- Lectures anticipées: 8
- Temps CPU 0
- Temps écoulé 23 ms
- Estimation du coût du sous-arbre: 0,0054782
- CompileCPU: 0
- CompileMemory: 192
- CompileTime: 0
Personnellement, même si Query 2 a un coût par lot plus élevé selon le plan graphique, je pense que c'est plus efficace que Query 1. Cela parce que la requête 2 nécessite moins de lectures logiques, a un temps écoulé légèrement inférieur, les valeurs compilecpu, compilememory et compiletime sont inférieur. les lectures avec lecture anticipée sont 8 pour la requête 2 et 0 pour la requête 1.
Mise à jour 12:03
Définition d'index clusterisé
ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
(
[orderid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Index non clusterisé idx_nc_custid
CREATE NONCLUSTERED INDEX [idx_nc_custid] ON [Sales].[Orders]
(
[custid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
la source
Réponses:
J'adore votre approche de l'examen minutieux de l'optimisation des requêtes et de l'examen des options et des plans. Je souhaite que plus de développeurs fassent cela. Une mise en garde serait - toujours tester avec beaucoup de lignes, en regardant les lectures logiques, c'est un petit tableau. Essayez de générer un exemple de charge et réexécutez la requête. Un petit problème - dans votre requête principale, vous ne demandez pas de commande par, dans votre requête inférieure, vous êtes. Vous devez les comparer et les contraster avec la commande.
Je viens de créer rapidement une table SalesOrders avec 200 000 commandes client - toujours pas énorme par tout effort d'imagination. Et exécuté les requêtes avec ORDER BY dans chacune. J'ai aussi joué un peu avec les index.
Sans index cluster sur OrderID, juste un index non cluster sur CustID La deuxième requête a surperformé. Surtout avec la commande incluse dans chacun. Il y avait deux fois plus de lectures sur la première requête que sur la deuxième requête, et les pourcentages de coût étaient de 67% / 33% entre les requêtes.
Avec un index cluster sur OrderID et un index non cluster uniquement sur CustID Ils ont effectué une vitesse similaire et le même nombre exact de lectures.
Je vous suggère donc d'augmenter le nombre de lignes et de faire d'autres tests. Mais ma dernière analyse sur vos requêtes -
Vous pouvez les voir se comporter de façon plus similaire que vous ne le pensez lorsque vous augmentez les rangées, alors gardez cette mise en garde à l'esprit et testez de cette façon.
Si tout ce que vous voulez retourner est le OrderID maximum pour chaque client, et vous voulez déterminer que le OrderID étant le plus grand OrderID, la deuxième requête parmi ces deux est la meilleure façon de partir de mon état d'esprit - c'est un peu plus simple et bien que légèrement plus cher en fonction du coût des sous-arbres, il s'agit d'une instruction plus rapide et plus facile à déchiffrer. Si vous avez l'intention d'ajouter un jour d'autres colonnes à votre jeu de résultats? Ensuite, la première requête vous permet de le faire.
Mise à jour: Un de vos commentaires sous votre question était:
Mais le meilleur moyen de le faire - tester avec plus de données - garantit toujours que vous disposez de données cohérentes avec la production et la production future attendue. Les plans de requête commencent à rechercher des données lorsque vous donnez plus de lignes aux tables et essayez de conserver la distribution comme vous l'attendez en production. Et faites attention à des choses comme inclure Order By ou non, ici, je ne pense pas que cela fasse une énorme différence à la fin, mais ça vaut quand même la peine de creuser.
Votre approche de comparaison de ce niveau de détail et de données est bonne. Les coûts des sous-arborescences sont arbitraires et dénués de sens pour la plupart, mais méritent tout de même d'être examinés pour comparer les modifications / modifications ou même les requêtes. Il est très important d'examiner les statistiques temporelles et les entrées-sorties, tout comme le plan pour tout ce qui semble déplacé par rapport à la taille des données avec lesquelles vous travaillez et ce que vous essayez de faire.
la source