Ich vergleiche zwei Abfragen in SQL Server 2012. Ziel ist es, alle relevanten Informationen des Abfrageoptimierers für die Auswahl der besten Abfrage zu verwenden. Beide Abfragen führen zu denselben Ergebnissen. die maximale Bestellnummer für alle Kunden.
Das Löschen des Pufferpools wurde vor dem Ausführen jeder Abfrage mit FREEPROCCACHE und DROPCLEANBUFFERS durchgeführt
Welche Abfrage ist unter Verwendung der unten angegebenen Informationen die bessere Wahl?
-- 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
STATISTIKEN ZEIT
Abfrage 1 STATISTIKZEIT: CPU-Zeit = 0 ms, verstrichene Zeit = 24 ms
Abfrage 2 STATISTIKZEIT: CPU-Zeit = 0 ms, verstrichene Zeit = 23 ms
STATISTIKEN IO
Abfrage 1 STATISTICS IO: Tabelle 'Orders'. Scananzahl 1, logische Lesevorgänge 5, physische Lesevorgänge 2, Vorauslesevorgänge 0, logische Lobs-Lesevorgänge 0, physikalische Lobs-Lesevorgänge 0, Lobs-Vorauslesevorgänge 0.
Abfrage 2 STATISTIK IO: Tabelle 'Bestellungen'. Scananzahl 1, logische Lesevorgänge 4, physische Lesevorgänge 1, Vorauslesevorgänge 8, logische Lobs-Lesevorgänge 0, physische Lobs-Lesevorgänge 0, Lobs-Vorauslesevorgänge 0.
Ausführungspläne
SELECT-Eigenschaften Abfrage 1
SELECT Eigenschaften Abfrage 2
Schlussfolgerungen:
Abfrage 1
- Batch-Kosten 48%
- Logische Lesevorgänge 5
- Physische Lesevorgänge 2
- Vorauslesen Liest: 0
- CPU-Zeit: 0ms
- Verstrichene Zeit 24ms
- Geschätzte Teilbaumkosten: 0.0050276
- CompileCPU: 2
- CompileMemory: 384
- CompileTime: 2
Abfrage 2
- Batch-Kosten 52%
- Logische Lesevorgänge 4
- Körperlesungen 1
- Vorauslesen Liest: 8
- CPU-Zeit 0
- Abgelaufene Zeit 23ms
- Geschätzte Teilbaumkosten: 0.0054782
- CompileCPU: 0
- CompileMemory: 192
- CompileTime: 0
Persönlich ist Abfrage 1 effizienter, obwohl Abfrage 2 laut Grafikplan höhere Batch-Kosten verursacht. Dies liegt daran, dass Abfrage 2 weniger logische Lesevorgänge erfordert, die verstrichene Zeit etwas kürzer ist als die Werte für Compilecpu, Compilememory und Compiletime niedriger. Read-Ahead-Reads sind 8 für Abfrage 2 und 0 für Abfrage 1.
Update 12.03
Definition des Clustered Index
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
Nicht gruppierter Index 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
quelle
Antworten:
Ich freue mich über Ihre Vorgehensweise bei der sorgfältigen Prüfung der Abfrageoptimierung und Überprüfung von Optionen und Plänen. Ich wünschte, mehr Entwickler hätten das getan. Eine Warnung wäre: Testen Sie immer mit vielen Zeilen und achten Sie auf die logischen Werte. Dies ist eine kleine Tabelle. Versuchen Sie, eine Beispiellast zu generieren und führen Sie die Abfrage erneut aus. Ein kleines Problem - in Ihrer oberen Abfrage fragen Sie nicht nach einer Bestellung von, in Ihrer unteren Abfrage sind Sie. Sie sollten sie jeweils mit der Bestellung vergleichen und gegenüberstellen.
Ich habe gerade schnell einen SalesOrders-Tisch mit 200.000 Kundenaufträgen erstellt. Und lief die Abfragen mit dem ORDER BY in jedem. Ich habe auch ein bisschen mit Indizes gespielt.
Ohne gruppierten Index für OrderID, nur einen nicht gruppierten Index für CustID. Die zweite Abfrage hat eine Outperformance erzielt . Vor allem bei der Bestellung von jeweils enthalten. Bei der ersten Abfrage wurden doppelt so viele Lesevorgänge ausgeführt wie bei der zweiten Abfrage, und die prozentualen Kosten zwischen den Abfragen betrugen 67% / 33%.
Mit einem Clustered-Index für OrderID und einem Non-Clustered-Index nur für CustID wurden sie mit einer ähnlichen Geschwindigkeit und genau der gleichen Anzahl von Lesevorgängen ausgeführt.
Daher würde ich vorschlagen, dass Sie die Anzahl der Zeilen erhöhen und weitere Tests durchführen. Aber meine abschließende Analyse Ihrer Fragen -
Sie können feststellen, dass sie sich ähnlicher verhalten, als Sie denken, wenn Sie die Zeilen vergrößern. Denken Sie also an diese Einschränkung, und testen Sie sie auf diese Weise.
Wenn alles, was Sie jemals zurückgeben möchten, die maximale Bestell-ID für jeden Kunden ist und Sie feststellen möchten, dass die Bestell-ID die größte Bestell-ID ist, ist die zweite Abfrage von diesen beiden der beste Weg aus meiner Sicht - es ist ein bisschen Einfacher und auf der Grundlage der Teilbaumkosten etwas teurer, ist es jedoch einfacher und schneller, Aussagen zu entschlüsseln. Möchten Sie eines Tages weitere Spalten zu Ihrer Ergebnismenge hinzufügen? Dann können Sie das mit der ersten Abfrage tun.
Aktualisiert: Einer Ihrer Kommentare zu Ihrer Frage lautete:
Der beste Weg, dies zu tun - testen Sie mit mehr Daten - stellt immer sicher, dass Sie Daten haben, die mit der Produktion und der erwarteten zukünftigen Produktion konsistent sind. Abfragepläne beginnen mit der Suche nach Daten, wenn Sie den Tabellen mehr Zeilen zuweisen und versuchen, die erwartete Verteilung in der Produktion beizubehalten. Und achten Sie auf Dinge wie "Order By" oder "Order By". Ich denke, dass es am Ende keinen großen Unterschied macht, aber es lohnt sich trotzdem, sich damit auseinanderzusetzen.
Ihr Ansatz, diese Detail- und Datenebene zu vergleichen, ist gut. Subtree-Kosten sind meist willkürlich und bedeutungslos, aber es lohnt sich immer noch, zumindest einen Vergleich zwischen Bearbeitungen / Änderungen oder sogar zwischen Abfragen anzustellen. Ein Blick auf die Zeitstatistik und das IO ist sehr wichtig, ebenso wie ein Blick auf den Plan für alles, was sich für die Größe der Daten, mit denen Sie arbeiten, und für das, was Sie tun möchten, als unangebracht anfühlt.
quelle