Ich habe die Tabelle big_table gemäß Ihrem Schema erstellt
create table big_table
(
updatetime datetime not null,
name char(14) not null,
TheData float,
primary key(Name,updatetime)
)
Ich habe dann die Tabelle mit 50.000 Zeilen mit diesem Code gefüllt:
DECLARE @ROWNUM as bigint = 1
WHILE(1=1)
BEGIN
set @rownum = @ROWNUM + 1
insert into big_table values(getdate(),'name' + cast(@rownum as CHAR), cast(@rownum as float))
if @ROWNUM > 50000
BREAK;
END
Mit SSMS habe ich dann beide Abfragen getestet und festgestellt, dass Sie in der ersten Abfrage nach dem MAX von TheData und in der zweiten nach dem MAX der Aktualisierungszeit suchen
Ich habe daher die erste Abfrage geändert, um auch die maximale Aktualisierungszeit zu erhalten
set statistics time on -- execution time
set statistics io on -- io stats (how many pages read, temp tables)
-- query 1
SELECT MAX([UpdateTime])
FROM big_table
-- query 2
SELECT MAX([UpdateTime]) AS value
from
(
SELECT [UpdateTime]
FROM big_table
group by [UpdateTime]
) as t
set statistics time off
set statistics io off
Mit Statistics Time erhalte ich die Anzahl der Millisekunden zurück, die zum Parsen, Kompilieren und Ausführen jeder Anweisung erforderlich sind
Mit Statistics IO erhalte ich Informationen zur Festplattenaktivität zurück
STATISTICS TIME und STATISTICS IO bieten nützliche Informationen. Zum Beispiel wurden temporäre Tabellen verwendet (angezeigt durch Arbeitstisch). Außerdem wurde angegeben, wie viele logische Seiten gelesen wurden, was die Anzahl der aus dem Cache gelesenen Datenbankseiten angibt.
Ich aktiviere dann den Ausführungsplan mit STRG + M (aktiviert den aktuellen Ausführungsplan anzeigen) und führe ihn dann mit F5 aus.
Dies bietet einen Vergleich beider Abfragen.
Hier ist die Ausgabe der Registerkarte Nachrichten
- Abfrage 1
Tabelle 'big_table'. Scananzahl 1, logische Lesevorgänge 543 , physische Lesevorgänge 0, Vorauslesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Lobvorlesevorgänge 0.
SQL Server-Ausführungszeiten:
CPU-Zeit = 16 ms, verstrichene Zeit = 6 ms .
- Abfrage 2
Tabelle ' Arbeitstisch '. Scananzahl 0, logische Lesevorgänge 0, physische Lesevorgänge 0, Vorauslesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Lobvorlesevorgänge 0.
Tabelle 'big_table'. Scananzahl 1, logische Lesevorgänge 543 , physische Lesevorgänge 0, Vorauslesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Lobvorlesevorgänge 0.
SQL Server-Ausführungszeiten:
CPU-Zeit = 0 ms, verstrichene Zeit = 35 ms .
Beide Abfragen führen zu 543 logischen Lesevorgängen, aber die zweite Abfrage hat eine verstrichene Zeit von 35 ms, während die erste nur 6 ms hat. Sie werden auch feststellen, dass die zweite Abfrage zur Verwendung temporärer Tabellen in tempdb führt, die durch das Wort Arbeitstabelle angezeigt werden . Obwohl alle Werte für den Arbeitstisch auf 0 liegen, wurde in tempdb noch gearbeitet.
Dann gibt es die Ausgabe von der Registerkarte " Ausführungsplan" neben der Registerkarte "Nachrichten"
Gemäß dem von MSSQL bereitgestellten Ausführungsplan hat die zweite von Ihnen bereitgestellte Abfrage Gesamtstapelkosten von 64%, während die erste nur 36% des Gesamtstapels kostet, sodass die erste Abfrage weniger Arbeit erfordert.
Mit SSMS können Sie Ihre Abfragen testen und vergleichen und genau herausfinden, wie MSSQL Ihre Abfragen analysiert und welche Objekte: Tabellen, Indizes und / oder Statistiken, falls vorhanden, um diese Abfragen zu erfüllen.
Eine zusätzliche Randnotiz, die Sie beim Testen beachten sollten, ist das Löschen des Caches vor dem Testen, wenn möglich. Dies hilft sicherzustellen, dass die Vergleiche korrekt sind, und dies ist wichtig, wenn Sie über die Festplattenaktivität nachdenken. Ich beginne mit DBCC DROPCLEANBUFFERS und DBCC FREEPROCCACHE , um den gesamten Cache zu leeren . Achten Sie jedoch darauf, diese Befehle nicht auf einem tatsächlich verwendeten Produktionsserver zu verwenden, da Sie den Server effektiv dazu zwingen, alles von der Festplatte in den Speicher zu lesen.
Hier ist die relevante Dokumentation.
- Leeren Sie den Plan-Cache mit DBCC FREEPROCCACHE
- Löschen Sie mit DBCC DROPCLEANBUFFERS alles aus dem Pufferpool
Die Verwendung dieser Befehle ist möglicherweise nicht möglich, je nachdem, wie Ihre Umgebung verwendet wird.
Aktualisiert 28.10. 12:46 Uhr
Das Ausführungsplan-Image und die Statistikausgabe wurden korrigiert.
getdate()
ich die Schleife verlassenDas Umschreiben hat möglicherweise geholfen, wenn SQL Server den Index-Skip-Scan implementiert hat, dies ist jedoch nicht der Fall.
Mit dem Index-Skip-Scan kann ein Datenbankmodul nach dem nächsthöheren Indexwert suchen, anstatt alle Duplikate (oder irrelevanten Unterschlüssel) dazwischen zu scannen. In Ihrem Fall würde das Überspringen des Scans es der Engine ermöglichen,
MAX(UpdateTime)
das erste zu findenName
, zumMAX(UpdateTime)
zweiten zuName
springen ... und so weiter. Der letzte Schritt wäre, dieMAX(UpdateTime)
Kandidaten aus einem Namen zu finden .Sie können dies bis zu einem gewissen Grad mit einem rekursiven CTE simulieren, aber es ist etwas chaotisch und nicht so effizient wie ein integrierter Skip-Scan:
Dieser Plan führt eine Singleton-Suche für jeden einzelnen
Name
durch und findet dann den höchstenUpdateTime
unter den Kandidaten. Die Leistung im Vergleich zu einem einfachen vollständigen Scan der Tabelle hängt davon ab, wie viele Duplikate pro vorhandenName
sind und ob sich die von den Singleton-Suchvorgängen berührten Seiten im Speicher befinden oder nicht.Alternativlösungen
Wenn Sie in der Lage sind, einen neuen Index für diese Tabelle zu erstellen, ist eine gute Wahl für diese Abfrage ein Index für
UpdateTime
:Dieser Index ermöglicht es der Ausführungs-Engine,
UpdateTime
mit einer Singleton-Suche bis zum Ende des Index-B-Baums den höchsten Wert zu finden :Dieser Plan benötigt nur wenige logische E / A-Vorgänge (um durch die B-Tree-Ebenen zu navigieren) und wird sofort abgeschlossen. Beachten Sie, dass der Index-Scan im Plan kein vollständiger Scan des neuen Index ist - er gibt lediglich eine Zeile vom einen Ende des Index zurück.
Wenn Sie keinen vollständig neuen Index für die Tabelle erstellen möchten, können Sie eine indizierte Ansicht in Betracht ziehen, die nur die eindeutigen
UpdateTime
Werte enthält:Dies hat den Vorteil, dass nur eine Struktur mit so vielen Zeilen erstellt wird, wie eindeutige
UpdateTime
Werte vorhanden sind. Bei jeder Abfrage, die Daten in der Basistabelle ändert, werden dem Ausführungsplan zusätzliche Operatoren hinzugefügt, um die indizierte Ansicht beizubehalten. Die Abfrage zum Finden des MaximalwertsUpdateTime
wäre:quelle