Soweit ich das beurteilen kann, können Sie einen Masseneinsatz auf sehr ähnliche Weise optimieren wie einen regulären Einsatz. Normalerweise ist ein Abfrageplan für eine einfache Einfügung nicht sehr informativ. Machen Sie sich also keine Sorgen, dass Sie den Plan nicht haben. Ich werde einige Möglichkeiten zur Optimierung einer Beilage durchgehen, aber die meisten davon gelten wahrscheinlich nicht für die Beilage, die Sie in der Frage angegeben haben. Sie können jedoch hilfreich sein, wenn Sie in Zukunft größere Datenmengen laden müssen.
1. Fügen Sie die Daten in der Reihenfolge der Clusterschlüssel ein
SQL Server sortiert Daten häufig, bevor sie in eine Tabelle mit einem Clustered-Index eingefügt werden. Bei einigen Tabellen und Anwendungen können Sie die Leistung verbessern, indem Sie die Daten in der Einfachdatei sortieren und SQL Server mitteilen, dass die Daten nach dem folgenden ORDER
Argument sortiert sind BULK INSERT
:
ORDER ({Spalte [ASC | DESC]} [, ... n])
Gibt an, wie die Daten in der Datendatei sortiert werden. Die Leistung des Massenimports wird verbessert, wenn die zu importierenden Daten gegebenenfalls nach dem Clustered-Index in der Tabelle sortiert werden.
Da Sie eine IDENTITY
Spalte als Clusterschlüssel verwenden, müssen Sie sich darüber keine Gedanken machen.
2. TABLOCK
Wenn möglich verwenden
Wenn Sie garantiert nur eine Sitzung haben, in der Daten in Ihre Tabelle eingefügt werden, können Sie das TABLOCK
Argument für angeben BULK INSERT
. Dies kann Sperrenkonflikte reduzieren und in einigen Szenarien zu einer minimalen Protokollierung führen . Sie fügen jedoch eine Tabelle mit einem Clustered-Index ein, der bereits Daten enthält, sodass Sie keine minimale Protokollierung ohne das Trace-Flag 610 erhalten, das später in dieser Antwort erwähnt wird.
Wenn dies TABLOCK
nicht möglich ist, weil Sie den Code nicht ändern können , ist nicht alle Hoffnung verloren. Erwägen Sie die Verwendung von sp_table_option
:
EXEC [sys].[sp_tableoption]
@TableNamePattern = N'dbo.BulkLoadTable' ,
@OptionName = 'table lock on bulk load' ,
@OptionValue = 'ON'
Eine andere Option besteht darin, das Ablaufverfolgungsflag 715 zu aktivieren .
3. Verwenden Sie eine geeignete Chargengröße
Manchmal können Sie Einsätze optimieren, indem Sie die Stapelgröße ändern.
ROWS_PER_BATCH = rows_per_batch
Gibt die ungefähre Anzahl von Datenzeilen in der Datendatei an.
Standardmäßig werden alle Daten in der Datendatei als einzelne Transaktion an den Server gesendet, und die Anzahl der Zeilen im Stapel ist dem Abfrageoptimierer unbekannt. Wenn Sie ROWS_PER_BATCH (mit einem Wert> 0) angeben, verwendet der Server diesen Wert, um den Massenimportvorgang zu optimieren. Der für ROWS_PER_BATCH angegebene Wert sollte ungefähr der tatsächlichen Anzahl der Zeilen entsprechen. Informationen zu Leistungsaspekten finden Sie unter "Anmerkungen" weiter unten in diesem Thema.
Hier ist das Zitat von später in dem Artikel:
Wenn die Anzahl der Seiten, die in einem einzelnen Stapel geleert werden sollen, einen internen Schwellenwert überschreitet, wird möglicherweise ein vollständiger Scan des Pufferpools durchgeführt, um festzustellen, welche Seiten geleert werden sollen, wenn der Stapel festgeschrieben wird. Dieser vollständige Scan kann die Leistung beim Massenimport beeinträchtigen. Ein wahrscheinlicher Fall des Überschreitens des internen Schwellenwerts tritt auf, wenn ein großer Pufferpool mit einem langsamen E / A-Subsystem kombiniert wird. Um Pufferüberläufe auf großen Computern zu vermeiden, verwenden Sie entweder nicht den TABLOCK-Hinweis (der die Massenoptimierungen entfernt) oder eine kleinere Stapelgröße (wodurch die Massenoptimierungen erhalten bleiben).
Da die Computer unterschiedlich sind, empfehlen wir, dass Sie verschiedene Stapelgrößen mit Ihrer Datenlast testen, um herauszufinden, was für Sie am besten funktioniert.
Persönlich würde ich einfach alle 695 Zeilen in einem einzigen Stapel einfügen. Das Einstellen der Stapelgröße kann jedoch beim Einfügen vieler Daten einen großen Unterschied machen.
4. Stellen Sie sicher, dass Sie die IDENTITY
Spalte benötigen
Ich weiß nichts über Ihr Datenmodell oder Ihre Anforderungen, aber geraten Sie nicht in die Falle IDENTITY
, jeder Tabelle eine Spalte hinzuzufügen . Aaron Bertrand hat einen Artikel darüber mit dem Titel " Schlechte Gewohnheiten": Auf jeden Tisch eine IDENTITY-Spalte setzen . Um es klar zu sagen, ich sage nicht, dass Sie die IDENTITY
Spalte aus dieser Tabelle entfernen sollten . Wenn Sie jedoch feststellen, dass die IDENTITY
Spalte nicht erforderlich ist, und sie entfernen, kann dies die Einfügeleistung verbessern.
5. Deaktivieren Sie Indizes oder Einschränkungen
Wenn Sie im Vergleich zu den bereits vorhandenen Daten eine große Datenmenge in eine Tabelle laden, ist es möglicherweise schneller, Indizes oder Einschränkungen vor dem Laden zu deaktivieren und nach dem Laden zu aktivieren. Bei großen Datenmengen ist es für SQL Server normalerweise ineffizienter, einen Index auf einmal zu erstellen, anstatt Daten in die Tabelle zu laden. Es sieht so aus, als hätten Sie 695 Zeilen in eine Tabelle mit 11500 Zeilen eingefügt, daher würde ich diese Technik nicht empfehlen.
6. Betrachten Sie TF 610
Das Trace-Flag 610 ermöglicht eine minimale Protokollierung in einigen zusätzlichen Szenarien. Für Ihre Tabelle mit einem IDENTITY
Clusterschlüssel erhalten Sie nur eine minimale Protokollierung für neue Datenseiten, solange Ihr Wiederherstellungsmodell einfach oder massenprotokolliert ist. Ich glaube, diese Funktion ist nicht standardmäßig aktiviert, da sie auf einigen Systemen die Leistung beeinträchtigen kann. Sie müssen sorgfältig testen, bevor Sie dieses Ablaufverfolgungsflag aktivieren. Die empfohlene Microsoft-Referenz scheint weiterhin The Data Loading Performance Guide zu sein
E / A-Auswirkung der minimalen Protokollierung unter Trace-Flag 610
Wenn Sie eine Bulk-Load-Transaktion festschreiben, die nur minimal protokolliert wurde, müssen alle geladenen Seiten vor Abschluss des Commits auf die Festplatte geschrieben werden. Alle geleerten Seiten, die nicht von einer früheren Prüfpunktoperation erfasst wurden, können eine Menge zufälliger E / A erzeugen. Vergleichen Sie dies mit einem vollständig protokollierten Vorgang, bei dem stattdessen sequenzielle E / A für die Protokollschreibvorgänge erstellt werden und keine geladenen Seiten zum Festschreibungszeitpunkt auf die Festplatte geschrieben werden müssen.
Wenn es sich bei Ihrem Ladeszenario um kleine Einfügevorgänge für Bäume handelt, die keine Prüfpunktgrenzen überschreiten, und Sie über ein langsames E / A-System verfügen, kann die Verwendung einer minimalen Protokollierung die Einfügegeschwindigkeit tatsächlich verlangsamen.
Soweit ich das beurteilen kann, hat dies nichts mit dem Trace-Flag 610 zu tun, sondern mit der minimalen Protokollierung. Ich glaube, das frühere Zitat über das ROWS_PER_BATCH
Stimmen kam zu demselben Konzept.
Zusammenfassend lässt sich sagen, dass Sie wahrscheinlich nicht viel tun können, um Ihre Einstellungen zu optimieren BULK INSERT
. Ich würde mir keine Sorgen um die Anzahl der Lesevorgänge machen, die Sie mit Ihrer Beilage beobachtet haben. SQL Server meldet jedes Mal Lesevorgänge, wenn Sie Daten einfügen. Betrachten Sie Folgendes sehr einfach INSERT
:
DROP TABLE IF EXISTS X_TABLE;
CREATE TABLE X_TABLE (
VAL VARCHAR(1000) NOT NULL
);
SET STATISTICS IO, TIME ON;
INSERT INTO X_TABLE WITH (TABLOCK)
SELECT REPLICATE('Z', 1000)
FROM dbo.GetNums(10000); -- generate 10000 rows
Ausgabe von SET STATISTICS IO, TIME ON
:
Tabelle 'X_TABLE'. Scananzahl 0, logische Lesevorgänge 11428
Ich habe 11428 Lesevorgänge gemeldet, aber das sind keine umsetzbaren Informationen. Manchmal kann die Anzahl der gemeldeten Lesevorgänge durch minimale Protokollierung reduziert werden, aber der Unterschied kann natürlich nicht direkt in einen Leistungsgewinn umgewandelt werden.