Ich habe eine Abfrage, bei der mit select *
nicht nur viel weniger Lesevorgänge, sondern auch deutlich weniger CPU-Zeit als mit select c.Foo
.
Dies ist die Abfrage:
select top 1000 c.ID
from ATable a
join BTable b on b.OrderKey = a.OrderKey and b.ClientId = a.ClientId
join CTable c on c.OrderId = b.OrderId and c.ShipKey = a.ShipKey
where (a.NextAnalysisDate is null or a.NextAnalysisDate < @dateCutOff)
and b.IsVoided = 0
and c.ComplianceStatus in (3, 5)
and c.ShipmentStatus in (1, 5, 6)
order by a.LastAnalyzedDate
Dies endete mit 2.473.658 logischen Lesevorgängen, hauptsächlich in Tabelle B. Es verwendete 26.562 CPU und hatte eine Dauer von 7.965.
Dies ist der generierte Abfrageplan:
Auf PasteThePlan: https://www.brentozar.com/pastetheplan/?id=BJAp2mQIQ
Wenn ich zu ändere c.ID
, *
wurde die Abfrage mit 107.049 logischen Lesevorgängen abgeschlossen, die ziemlich gleichmäßig auf alle drei Tabellen verteilt waren. Es verwendete 4.266 CPU und hatte eine Laufzeit von 1.147.
Dies ist der generierte Abfrageplan:
Auf PasteThePlan: https://www.brentozar.com/pastetheplan/?id=SyZYn7QUQ
Ich habe versucht, die von Joe Obbish vorgeschlagenen Abfragehinweise mit den folgenden Ergebnissen zu verwenden:
select c.ID
ohne Hinweis: https://www.brentozar.com/pastetheplan/?id=SJfBdOELm
select c.ID
mit Hinweis: https://www.brentozar.com/pastetheplan/ ? id = B1W ___ N87
select *
ohne Hinweis: https://www.brentozar.com/pastetheplan/?id=HJ6qddEIm
select *
mit Hinweis: https://www.brentozar.com/pastetheplan/?id=rJhhudNIQ
Durch die Verwendung des OPTION(LOOP JOIN)
Hinweises mit wurde select c.ID
die Anzahl der Lesevorgänge im Vergleich zur Version ohne Hinweis drastisch reduziert, es wird jedoch immer noch etwa die vierfache Anzahl der Lesevorgänge für die select *
Abfrage ohne Hinweise ausgeführt. Das Hinzufügen OPTION(RECOMPILE, HASH JOIN)
zu der select *
Abfrage hat die Leistung wesentlich verschlechtert als alles, was ich bisher versucht habe.
Nach dem Aktualisieren der Statistiken für die Tabellen und ihre Indizes mithilfe von WITH FULLSCAN
wird die select c.ID
Abfrage viel schneller ausgeführt:
select c.ID
Vor dem Update: https://www.brentozar.com/pastetheplan/?id=SkiYoOEUm
select *
Vor dem Update: https://www.brentozar.com/ pastetheplan /? id = ryrvodEUX
select c.ID
nach dem Update: https://www.brentozar.com/pastetheplan/?id=B1MRoO487
select *
nach dem Update: https://www.brentozar.com/pastetheplan/?id=Hk7si_V8m
select *
Immer noch besser als die select c.ID
Gesamtdauer und die Gesamtanzahl der Lesevorgänge ( select *
hat etwa die Hälfte der Lesevorgänge), verbraucht jedoch mehr CPU. Insgesamt sind sie viel näher als vor dem Update, jedoch unterscheiden sich die Pläne immer noch.
Das gleiche Verhalten ist für 2016 im Kompatibilitätsmodus 2014 und für 2014 zu beobachten. Was könnte die Diskrepanz zwischen den beiden Plänen erklären? Könnte es sein, dass die "richtigen" Indizes nicht erstellt wurden? Könnten leicht veraltete Statistiken dazu führen?
Ich habe versucht, ON
die Vergleichselemente auf mehrere Arten in den Teil des Joins zu verschieben, aber der Abfrageplan ist jedes Mal derselbe.
Nach Index-Neuerstellungen
Ich habe alle Indizes für die drei an der Abfrage beteiligten Tabellen neu erstellt. c.ID
führt immer noch die meisten Lesevorgänge aus (mehr als doppelt so viele *
), die CPU-Auslastung beträgt jedoch etwa die Hälfte der *
Version. Die c.ID
Version auch verschüttete in tempdb auf die Sortierung von ATable
:
c.ID
: https://www.brentozar.com/pastetheplan/?id=HyHIeDO87
*
: https://www.brentozar.com/pastetheplan/?id=rJ4deDOIQ
Ich habe auch versucht, den Betrieb ohne Parallelität zu erzwingen. Dies ergab die beste Abfrage: https://www.brentozar.com/pastetheplan/?id=SJn9-vuLX
Ich bemerke die Ausführungsanzahl der Operatoren NACH dem großen Index-Suchvorgang, bei dem die Bestellung in der Singlethread-Version nur 1.000 Mal ausgeführt wird, in der parallelisierten Version jedoch deutlich mehr, und zwar zwischen 2.622 und 4.315 Ausführungen verschiedener Operatoren.
select c.ID
Abfrage wurde dadurch viel schneller, es wird jedoch noch zusätzliche Arbeit geleistet, die dieselect *
Abfrage ohne Hinweise leistet.