Fehler bei der Neuerstellung unter SQL Server 2016 und höher?

7

Zusammenfassung der Fragen

Ein fragmentierter Clustered-Index funktioniert auch nach einem Index nicht gut REBUILD. Wenn der Index ist, REORGANIZEDerhö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

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Crystal Disk Mark Testergebnisse

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

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_allocationses 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 DROPCLEANBUFFERSdaher ü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

3 Test

4 Probleme beim Wiederaufbau

5 Daten in neue Tabelle einfügen

Links: (Google Drive)

6 Download Ergebnis auf meinen Systemen

Neeraj Prasad Sharma
quelle
Kommentare sind nicht für eine ausführliche Diskussion gedacht. Dieses Gespräch wurde in den Chat verschoben . Bitte verwenden Sie diese Funktion zur weiteren Fehlerbehebung.
Paul White 9

Antworten:

13

Die fraglichen Abfragen üben die Vorauslesefunktion von SQL Server aus . Mit der Read-Ahead-Leistungsoptimierung ruft die SQL Server-Speicher-Engine Daten während der Scans vorab ab, sodass sich die Seiten bei Bedarf für die Abfrage bereits im Puffer-Cache befinden, sodass weniger Zeit für das Warten auf Daten während der Abfrageausführung aufgewendet wird.

Der Unterschied in den Ausführungszeiten mit Read-Alead spiegelt wider, wie gut (oder nicht) das Speichersystem und die Windows-APIs mit großen E / A-Größen umgehen, sowie Unterschiede im Vorlesungsverhalten von SQL Server, die je nach Version variieren. Ältere SQL Server-Versionen (SQL Server 2008 R2 im oben genannten Artikel) beschränken Prefeatch auf 512 KB-E / A-Größen, während SQL Server 2016 und spätere E / A-Vorlesungen in größeren Größen die Funktionen moderner Standardhardware (RAID und SSD) nutzen. Beachten Sie, dass SQL Server zum Zeitpunkt der Veröffentlichung im Allgemeinen für die Ausführung auf Hardware der aktuellen Generation optimiert ist und dabei den größeren Prozessor-Cache, die NUMA-Architektur und die IOPS- / Bandbreitenfähigkeit des Speichersystems ausnutzt. Darüber hinaus führen Enterprise / Developer-Editionen den Prefetch aggressiver aus als kleinere Editionen, um den Durchsatz noch weiter zu maximieren.

Um den Grund für die unterschiedliche Leistung von SQL 2008 R2 im Vergleich zu späteren Versionen besser zu verstehen, habe ich eine geänderte Version Ihrer Skripts auf einem älteren physischen Computer mit verschiedenen Versionen von SQL Server Developer Edition ausgeführt. Diese Testbox verfügt sowohl über eine Festplatte mit 7200 U / min als auch über eine SATA-SSD, sodass derselbe Test auf demselben Computer für verschiedene Speichersysteme und SQL-Versionen ausgeführt werden kann. Ich habe während jedes Tests die Ereignisse file_read und file_read_completed mit einer erweiterten Ereignisablaufverfolgung erfasst, um eine detailliertere Analyse der E / A und des Timings zu erhalten.

Die Ergebnisse zeigen eine ungefähr vergleichbare Leistung mit allen SQL Server-Versionen und Speichersystemtypen mit Ausnahme von SQL Server 2012 und späteren Versionen auf einer einzelnen Festplattenspindel nach der Neuerstellung des Clustered-Index. Interessanterweise zeigte der XE-Trace nur bei Vorauslesevorgängen in SQL Server 2008 R2 den Modus "Fortlaufend". Die Ablaufverfolgung zeigte, dass der "Scatter / Gather" -Modus in allen anderen Versionen verwendet wurde. Ich kann nicht sagen, ob dieser Unterschied zur schnelleren Leistung beiträgt.

Die Analyse der Trace-Daten zeigt außerdem, dass SQL 2016 bei Read-Ahead-Scans viel größere Lesevorgänge ausführt und die durchschnittliche E / A-Größe je nach Speichertyp variiert. Dies bedeutet nicht unbedingt, dass SQL Server die Größe der vorauslesbaren E / A basierend auf der physischen Hardware anpasst, sondern dass die Größe möglicherweise basierend auf unbekannten Messungen angepasst wird. Die von der Speicher-Engine verwendeten Heuristiken sind nicht dokumentiert und können je nach Version und Patch-Level variieren.

Unten finden Sie eine Zusammenfassung der Testzeiten. Ich werde weitere Informationen aus den Traces hinzufügen, wenn ich mehr Zeit habe (leider ist die E / A-Größe in SQL Server 2008 R2 XE nicht verfügbar). Zusammenfassend unterscheidet sich das E / A-Profil je nach Version und Speichertyp. Die durchschnittliche E / A-Größe für Versionen über SQL Server 2014 hat 512 KB nie überschritten, während SQL Server 2016 in diesen Tests mehr als 4 MB in einem einzelnen E / A gelesen hat. Die Anzahl der ausstehenden Lesevorgänge war im SQL 2016-Test ebenfalls viel geringer, da SQL Server weniger E / A-Anforderungen hat, um dieselbe Arbeit auszuführen.

SQL_Version Storage Device         Test                   Duration
SQL 2008 R2    HDD             initial table            00:00:03.686
SQL 2012       HDD             initial table            00:00:03.725
SQL 2014       HDD             initial table            00:00:03.706
SQL 2016       HDD             initial table            00:00:03.654
SQL 2008 R2    HDD             fragmented table         00:00:07.796
SQL 2012       HDD             fragmented table         00:00:08.026
SQL 2014       HDD             fragmented table         00:00:07.837
SQL 2016       HDD             fragmented table         00:00:06.097
SQL 2008 R2    HDD             after rebuild            00:00:06.962
SQL 2012       HDD             after rebuild            00:00:21.129
SQL 2014       HDD             after rebuild            00:00:19.501
SQL 2016       HDD             after rebuild            00:00:21.377
SQL 2008 R2    HDD             after reorg              00:00:04.103
SQL 2012       HDD             after reorg              00:00:03.974
SQL 2014       HDD             after reorg              00:00:04.076
SQL 2016       HDD             after reorg              00:00:03.610
SQL 2008 R2    HDD             after reorg and rebuild  00:00:07.201
SQL 2012       HDD             after reorg and rebuild  00:00:21.839
SQL 2014       HDD             after reorg and rebuild  00:00:20.199
SQL 2016       HDD             after reorg and rebuild  00:00:21.782
SQL 2008 R2    SATA SSD        initial table            00:00:02.083
SQL 2012       SATA SSD        initial table            00:00:02.071
SQL 2014       SATA SSD        initial table            00:00:02.074
SQL 2016       SATA SSD        initial table            00:00:02.066
SQL 2008 R2    SATA SSD        fragmented table         00:00:03.134
SQL 2012       SATA SSD        fragmented table         00:00:03.129
SQL 2014       SATA SSD        fragmented table         00:00:03.129
SQL 2016       SATA SSD        fragmented table         00:00:03.113
SQL 2008 R2    SATA SSD        after rebuild            00:00:02.065
SQL 2012       SATA SSD        after rebuild            00:00:02.097
SQL 2014       SATA SSD        after rebuild            00:00:02.071
SQL 2016       SATA SSD        after rebuild            00:00:02.078
SQL 2008 R2    SATA SSD        after reorg              00:00:02.064
SQL 2012       SATA SSD        after reorg              00:00:02.082
SQL 2014       SATA SSD        after reorg              00:00:02.067
SQL 2016       SATA SSD        after reorg              00:00:02.072
SQL 2008 R2    SATA SSD        after reorg and rebuild  00:00:02.078
SQL 2012       SATA SSD        after reorg and rebuild  00:00:02.087
SQL 2014       SATA SSD        after reorg and rebuild  00:00:02.087
SQL 2016       SATA SSD        after reorg and rebuild  00:00:02.079

Ich habe diese Tests auch auf einer VM mit einem HDD-gestützten SAN ausgeführt und eine ähnliche Leistung wie bei der SATA-SSD festgestellt. Unter dem Strich tritt dieses Leistungsproblem nur bei einer einspindeligen HDD-Datendatei auf, was nur auf PCs und nicht auf modernen Produktionssystemen üblich ist. Ob dies als Leistungsregressionsfehler angesehen werden sollte oder nicht, ist fraglich, aber ich werde mich bemühen, weitere Informationen zu erhalten.

BEARBEITEN

Ich habe mich an meine Kontakte gewandt und Erland Sommarskog hat auf die höhere Fragmentanzahl hingewiesen, die von sys.dm_db_index_physical_stats in späteren Versionen gemeldet wurde. Als ich tiefer grub, bemerkte ich, dass die REBUILD-Anweisung eine parallele Abfrage ist. Die Implikation ist, dass eine parallele Neuerstellung tatsächlich die Fragmentanzahl erhöhen kann (und sogar eine Fragmentierung in einer Tabelle ohne Fragmentierung einführt), da die Speicherplatzzuweisungen parallel erfolgen. Dies wirkt sich im Allgemeinen nicht auf die Leistung aus, außer bei Read-Ahead-Scans, und ist insbesondere bei Einzelspindel-Spinnmedien ein Problem, wie die Tests zeigen. Dies ist in allen SQL-Versionen eine Überlegung.

Paul Randal wies darauf hin und bezog sich auf dieses Dokument, um weitere Informationen zu erhalten. Eine bewährte Methode für Indexwiederherstellungen für eine Workload, die Read-Ahead-Scans (z. B. Data Warehousing) nutzt, ist die Neuerstellung WITH (MAXDOP = 1).

Dan Guzman
quelle