Zusammenfassung der Fragen
Ein fragmentierter Clustered-Index funktioniert auch nach einem Index nicht gut REBUILD
. Wenn der Index ist, REORGANIZED
erhöht sich die Leistung für die angegebene Tabelle / den angegebenen Index.
Ich sehe dieses ungewöhnliche Verhalten nur unter SQL Server 2016 und höher. Ich habe dieses Szenario auf unterschiedlicher Hardware und verschiedenen Versionen getestet (alle PCs und alle haben die herkömmliche rotierende Festplatte). Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen.
Ist dies ein Fehler in SQL Server 2016 und höher?
Ich kann die vollständigen Details und Analysen mit dem Skript bereitstellen, wenn jemand dies wünscht, aber momentan nicht, da das Skript ziemlich groß ist und viel Platz in der Frage beansprucht.
Testen Sie die kürzere Version des Beispielskripts aus dem unten angegebenen Link in Ihrer DEV-Umgebung, wenn Sie über SQL Server 2016 und höher verfügen.
SKRIPT
-- SECTION 1
/*
Create a Test Folder in the machine and spefiy the drive in which you created
*/
USE MASTER
CREATE DATABASE RebuildTest
ON
( NAME = 'RebuildTest',
FILENAME = 'F:\TEST\RebuildTest_db.mdf',
SIZE = 200MB,
MAXSIZE = UNLIMITED,
FILEGROWTH = 50MB )
LOG ON
( NAME = 'RebuildTest_log',
FILENAME = 'F:\TEST\RebuildTest_db.ldf',
SIZE = 100MB,
MAXSIZE = UNLIMITED,
FILEGROWTH = 10MB ) ;
GO
BEGIN TRAN
USE RebuildTest
select top 1000000
row_number () over ( order by (Select null)) n into Numbers from
sys.all_columns a cross join sys.all_columns
CREATE TABLE [DBO].FRAG3 (
Primarykey int NOT NULL ,
SomeData3 char(1000) NOT NULL )
ALTER TABLE DBO.FRAG3
ADD CONSTRAINT PK_FRAG3 PRIMARY KEY (Primarykey)
INSERT INTO [DBO].FRAG3
SELECT n , 'Some text..'
FROM Numbers
Where N/2 = N/2.0
Update DBO.FRAG3 SET Primarykey = Primarykey-500001
Where Primarykey>500001
COMMIT
-- SECTION 2
SELECT @@VERSION
/* BEGIN PART FRAG1.1 */
----- BEGIN CLEANBUFFER AND DATABASE AND MEASURE TIME
CHECKPOINT;
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
SET STATISTICS TIME ON
Select Count_Big (*) From [DBO].[FRAG3] Where Primarykey >0 Option (MAxDop 1)
SET STATISTICS TIME OFF
----- END CLEANBUFFER AND DATABASE AND MEASURE TIME
-------------BEGIN PART FRAG1.2: REBUILD THE INDEX AND TEST AGAIN
--BEGIN Rebuild the Index
Alter Table [DBO].[FRAG3] REBUILD
--END Rebuild the Index
----- BEGIN CLEANBUFFER FROM DATABASE AND MEASURE TIME
CHECKPOINT;
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
SET STATISTICS TIME ON
Select Count_Big (*) From [DBO].[FRAG3] Where Primarykey >0 Option (MAxDop 1)
SET STATISTICS TIME OFF
----- END CLEANBUFFER FROM DATABASE AND MEASURE TIME
--BEGIN REORGANIZE the Index
ALTER INDEX ALL ON [DBO].[FRAG3] REORGANIZE ;
--END REORGANIZE the Index
----- BEGIN CLEANBUFFER FROM DATABASE AND MEASURE TIME
CHECKPOINT;
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
SET STATISTICS TIME ON
Select Count_Big (*) From [DBO].[FRAG3] Where Primarykey >0 Option (MAxDop 1)
SET STATISTICS TIME OFF
----- END CLEANBUFFER FROM DATABASE AND MEASURE TIME
-------------BEGIN PART FRAG1.4: REBUILD THE INDEX AND TEST AGAIN
--BEGIN Rebuild the Index
Alter Table [DBO].[FRAG3] REBUILD
--END Rebuild the Index
----- BEGIN CLEANBUFFER FROM DATABASE AND MEASURE TIME
CHECKPOINT;
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
SET STATISTICS TIME ON
Select Count_Big (*) From [DBO].[FRAG3] Where Primarykey >0 Option (MAxDop 1)
SET STATISTICS TIME OFF
----- END CLEANBUFFER FROM DATABASE AND MEASURE TIME
-------------END PART FRAG1.4: REBUILD THE INDEX AND TEST AGAIN
Ergebnisse
Crystal Disk Mark Testergebnisse
Detail
Ich sehe ein ungewöhnliches Verhalten der Speicher-Engine (möglicherweise) unter SQL Server 2016 und höher. Ich habe eine stark fragmentierte Tabelle für (Leseprobleme mit Fragmentierung) Demo-Zwecke erstellt und sie dann neu erstellt.
Auch nach dem Wiederaufbau steigt die Indexleistung nicht wie erwartet. Um sicherzustellen, dass das Datenzugriffsmuster in Schlüsselreihenfolge und nicht in IAM-gesteuertem Scan (Allocation Order Scan) vorliegt, habe ich das Bereichsprädikat verwendet.
Anfangs dachte ich, dass SQL Server 2016 und höher für große Scans möglicherweise aggressiver ist. Um dies zu überprüfen, habe ich die Seitenzahl und die Zeilenanzahl angepasst, aber das Leistungsmuster ändert sich nicht. Ich habe alles auf einem persönlichen System getestet, damit ich sagen kann, dass keine andere Benutzeraktivität stattgefunden hat.
Ich habe dieses Verhalten auch auf anderer Hardware getestet ( alle haben herkömmliche rotierende Festplatten ). Leistungsmuster sind fast gleich.
Ich habe überprüft, dass die Wartestatistiken dort nur normal erscheinen PAGELATCH_IO
(mit Paul Randal-Skript). Ich habe Datenseiten mit DMV überprüft, sys.dm_db_database_page_allocations
es scheint auch in Ordnung zu sein.
Wenn ich die Tabelle neu organisiere oder alle Daten in eine neue Tabelle mit derselben Indexdefinition verschiebe, erhöht sich die E / A-Leistung der Festplatte. Ich habe dies mit perfmon überprüft und es scheint, dass eine Neuorganisation des Index / einer neuen Tabelle sequentielle E / A und den Wiederherstellungsindex nutzen kann, wobei immer noch die zufälligen Lesevorgänge verwendet werden, obwohl beide fast die gleiche interne und externe Fragmentierung der Datenseiten aufweisen.
Ich füge die vollständige Abfrage mit den Ergebnissen auf meinem System hinzu, die ich erfasst habe. Wenn Sie SQL Server 2016 und höher DEV-Box haben, überprüfen Sie dies bitte und teilen Sie Ihre Ergebnisse.
WARNUNG : Dieser Test besteht aus einigen undokumentierten Befehlen und wird DROPCLEANBUFFERS
daher überhaupt nicht auf dem Produktionsserver ausgeführt.
Wenn dies wirklich ein Fehler ist, sollte ich ihn einreichen.
Die Frage ist also: Ist es wirklich ein Fehler oder fehlt mir etwas;)
Links (Pastebin)
1 Fragmentierte Tabellenerstellung
2 Unterstützende SPs LAUFEN NACH DER TABELLENERSTELLUNG
5 Daten in neue Tabelle einfügen