Ich habe Testdaten verspottet, die Ihr Problem hauptsächlich reproduzieren:
INSERT INTO [dbo].[TestTable] WITH (TABLOCK)
SELECT TOP (7000000) N'*NOT GDPR*', N'*NOT GDPR*', N'*NOT GDPR*', 0, DATEADD(DAY, q.RN / 16965, '20160801')
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) q
ORDER BY q.RN
OPTION (MAXDOP 1);
DROP INDEX IF EXISTS [dbo].[TestTable].IX_TestTable_Date;
CREATE NONCLUSTERED INDEX IX_TestTable_Date ON [dbo].[TestTable] ([Date]);
Statistiken für die Abfrage, die den nicht gruppierten Index verwendet:
Tabelle 'TestTable'. Scananzahl 1, logische Lesevorgänge 1299838, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Vorlesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 984 ms, verstrichene Zeit = 988 ms.
Statistiken für die Abfrage, die den Clustered-Index verwendet:
Tabelle 'TestTable'. Scananzahl 1, logische Lesevorgänge 72609, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Vorlesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 781 ms, verstrichene Zeit = 772 ms.
Kommen wir zu Ihrer Frage:
Ist es möglich, diese Tatsache zu nutzen, um die Leistung meiner Abfrage zu verbessern?
Ja. Sie können den nicht gruppierten Index verwenden, den Sie bereits id
benötigen, um den Maximalwert , der aktualisiert werden muss, effizient zu ermitteln . Wenn Sie dies in einer Variablen speichern und danach filtern, erhalten Sie einen Abfrageplan für das Update, der den Clustered-Index-Scan (ohne Sortierung) durchführt, der vorzeitig beendet wird und daher weniger E / A ausführt. Hier ist eine Implementierung:
DECLARE @Id INT;
SELECT TOP (1) @Id = Id
FROM dbo.TestTable
WHERE [Date] <= '25 August 2016'
ORDER BY [Date] DESC, Id DESC;
UPDATE TestTable
SET TestCol='*GDPR*', TestCol2='*GDPR*', TestCol3='*GDPR*', Anonymised=1
WHERE [Id] < @Id AND [Date] <= '25 August 2016'
AND [Anonymised] <> 1 -- optional
OPTION (MAXDOP 1);
Führen Sie Statistiken für die neue Abfrage aus:
Tabelle 'TestTable'. Scananzahl 1, logische Lesevorgänge 3, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Lobvorlesevorgänge 0.
Tabelle 'TestTable'. Scananzahl 1, logische Lesevorgänge 4776, physische Lesevorgänge 0, Vorlesevorgänge 0, Lob-Lesevorgänge 0, Lob-Lesevorgänge 0, Vorlesevorgänge 0.
SQL Server-Ausführungszeiten: CPU-Zeit = 515 ms, verstrichene Zeit = 510 ms.
Sowie der Abfrageplan:
Nach alledem lässt Ihr Wunsch, die Abfrage schneller zu machen, darauf schließen, dass Sie die Abfrage mehrmals ausführen möchten. Im Moment hat Ihre Abfrage einen offenen Filter für die date
Spalte. Ist es wirklich notwendig, die Zeilen mehr als einmal zu anonymisieren? Können Sie vermeiden, bereits anonymisierte Zeilen zu aktualisieren oder zu scannen? Es sollte auf jeden Fall schneller sein, eine Reihe von Daten mit Daten auf beiden Seiten zu aktualisieren. Sie können die Anonymised
Spalte auch zu Ihrem Index hinzufügen , dieser Index muss jedoch während Ihrer UPDATE
Abfrage aktualisiert werden. Zusammenfassend lässt sich sagen, dass Sie es vermeiden sollten, dieselben Daten immer wieder zu verarbeiten, wenn Sie können.
Die ursprüngliche Abfrage, die Sie mit der Sortierung haben, ist aufgrund der im Clustered Index Update
Operator ausgeführten Arbeit langsamer . Die für die Indexsuche und -sortierung aufgewendete Zeit beträgt nur 407 ms. Sie können dies im aktuellen Plan sehen. Der Plan wird im Zeilenmodus ausgeführt, sodass die für die Sortierung aufgewendete Zeit die Zeit dieses Operators zusammen mit jedem untergeordneten Operator ist:
Damit bleibt dem Sortieroperator etwa 1600 ms Zeit. SQL Server muss Seiten aus dem Clustered-Index lesen, um die Aktualisierung durchzuführen. Sie können sehen, dass der Clustered Index Update
Operator 1205921 logische Lesevorgänge ausführt. Weitere Informationen zum Sortieren von Optimierungen für DML und zum optimierten Prefetch finden Sie in diesem Blogbeitrag von Paul White .
Der andere Abfrageplan, den Sie (ohne Sortierung) haben, benötigt 683 ms für den Clustered-Index-Scan und etwa 550 ms für den Clustered Index Update
Operator. Der Aktualisierungsoperator führt für diese Abfrage keine E / A durch.
Die einfache Antwort darauf, warum der Plan mit der Sortierung langsamer ist, besteht darin, dass SQL Server den Clustered-Index für diesen Plan logischer liest als der Clustered-Index-Scan-Plan. Selbst wenn sich alle benötigten Daten im Speicher befinden, ist der Aufwand und die Kosten für diese logischen Lesevorgänge immer noch hoch. Eine bessere Antwort ist viel schwieriger zu bekommen, da die Pläne meines Wissens keine weiteren Details enthalten. Es ist möglich, PerfView oder ein anderes auf ETW-Tracing basierendes Tool zu verwenden, um Anrufstapel zwischen den Abfragen zu vergleichen:
Links befindet sich die Abfrage, die den Clustered-Index-Scan durchführt, und rechts die Abfrage, die die Sortierung durchführt. Ich habe Anrufstapel blau oder rot markiert, die nur in einer Abfrage angezeigt werden. Es überrascht nicht, dass die verschiedenen Aufrufstapel mit einer hohen Anzahl von abgetasteten CPU-Zyklen für die Sortierabfrage mit den logischen Lesevorgängen zu tun zu haben scheinen, die zum Durchführen der Aktualisierung des Clustered-Index erforderlich sind. Darüber hinaus gibt es Unterschiede in der Anzahl der abgetasteten Zyklen zwischen den Abfragen für dieselbe Operation. Zum Beispiel benötigt die Abfrage mit der Sortierung 31 Zyklen zum Erfassen von Latches, während die Abfrage mit dem Scan nur 9 Zyklen zum Erfassen von Latches benötigt.
Ich vermute, dass SQL Server den langsameren Plan aufgrund einer Kostenbeschränkung für den Abfrageplan-Operator auswählt. Möglicherweise ist ein Teil des Unterschieds in der Laufzeit auf die Hardware oder Ihre Edition von SQL Server zurückzuführen. In jedem Fall kann SQL Server nicht herausfinden, dass die Datumsspalte implizit genau so geordnet ist wie der Clustered-Index. Die Daten werden vom Clustered-Index-Scan in der Reihenfolge der Clustered-Schlüssel zurückgegeben, sodass beim Sortieren der Clustered-Index-Aktualisierung keine Sortierung durchgeführt werden muss, um die E / A zu optimieren.