it-swarm.com.de

Wie untersucht man die Leistung einer BULK INSERT-Anweisung?

Ich bin hauptsächlich ein .NET-Entwickler, der Entity Framework ORM verwendet. Da ich jedoch nicht möchte, dass die Verwendung des ORM fehlschlägt , versuche ich zu verstehen, was innerhalb der Datenschicht (Datenbank) geschieht. Grundsätzlich starte ich während der Entwicklung den Profiler und überprüfe, was einige Teile des Codes in Bezug auf Abfragen generieren.

Wenn ich etwas äußerst Kompliziertes (ORM kann selbst aus ziemlich einfachen LINQ-Anweisungen, wenn es nicht sorgfältig geschrieben wurde, schreckliche Abfragen erzeugen kann) und/oder schwer (Dauer, CPU, Seitenlesevorgänge) finde, nehme ich es in SSMS und überprüfe seinen Ausführungsplan.

Es funktioniert gut für meine Datenbankkenntnisse. BULK INSERT scheint jedoch eine besondere Kreatur zu sein, da es scheint kein SHOWPLAN zu produzieren .

Ich werde versuchen, ein sehr einfaches Beispiel zu veranschaulichen:

Tabellendefinition

CREATE TABLE dbo.ImportingSystemFileLoadInfo
(
    ImportingSystemFileLoadInfoId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_ImportingSystemFileLoadInfo PRIMARY KEY CLUSTERED,
    EnvironmentId INT NOT NULL CONSTRAINT FK_ImportingSystemFileLoadInfo REFERENCES dbo.Environment,
    ImportingSystemId INT NOT NULL CONSTRAINT FK_ImportingSystemFileLoadInfo_ImportingSystem REFERENCES dbo.ImportingSystem,
    FileName NVARCHAR(64) NOT NULL,
FileImportTime DATETIME2 NOT NULL,
    CONSTRAINT UQ_ImportingSystemImportInfo_EnvXIs_TableName UNIQUE (EnvironmentId, ImportingSystemId, FileName, FileImportTime)
)

Hinweis: In der Tabelle sind keine weiteren Indizes definiert

Die Masseneinfügung (was ich im Profiler fange, nur eine Charge)

insert bulk [dbo].[ImportingSystemFileLoadInfo] ([EnvironmentId] Int, [ImportingSystemId] Int, [FileName] NVarChar(64) COLLATE Latin1_General_CI_AS, [FileImportTime] DateTime2(7))

Metriken

  • 695 Artikel eingefügt
  • CPU = 31
  • Reads = 4271
  • Schreibt = 24
  • Dauer = 154
  • Gesamtzahl der Tabellen = 11500

Für meine Anwendung ist das in Ordnung, obwohl die Lesevorgänge ziemlich groß erscheinen (ich weiß sehr wenig über SQL Server-Interna, daher vergleiche ich sie mit der 8-KB-Seitengröße und den kleinen Datensatzinformationen, die ich habe).

Frage: Wie kann ich untersuchen, ob dieser BULK INSERT optimiert werden kann? Oder macht es keinen Sinn, da es wohl der schnellste Weg ist, große Datenmengen von einer Clientanwendung auf SQL Server zu übertragen?

12
Alexei

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. Daten in Clustering-Schlüsselreihenfolge einfügen

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 darüber informieren, dass die Daten über das Argument ORDER von BULK INSERT Sortiert werden. ::

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. Verwenden Sie nach Möglichkeit TABLOCK

Wenn Sie garantiert nur eine Sitzung haben, in der Daten in Ihre Tabelle eingefügt werden, können Sie das Argument TABLOCK für BULK INSERT Angeben. Dies kann Sperrenkonflikte reduzieren und in einigen Szenarien zu minimale Protokollierung führen. Sie fügen jedoch eine Tabelle mit einem Clustered-Index ein, der bereits Daten enthält, sodass Sie ohne das Trace-Flag 610, das später in dieser Antwort erwähnt wird, keine minimale Protokollierung erhalten.

Wenn TABLOCK nicht möglich ist, weil Sie können den Code nicht ändern , 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 ist die Aktivierung von Trace-Flag 715 .

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 beim Festschreiben des Stapels geleert werden sollen. 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 Spalte IDENTITY benötigen

Ich weiß nichts über Ihr Datenmodell oder Ihre Anforderungen, aber geraten Sie nicht in die Falle, jeder Tabelle eine IDENTITY - Spalte hinzuzufügen. Aaron Bertrand hat einen Artikel darüber mit dem Titel Schlechte Gewohnheiten zu treten: Setzen Sie eine IDENTITY-Spalte auf jeden Tisch . Um es klar auszudrücken, sage ich nicht, dass Sie die Spalte IDENTITY aus dieser Tabelle entfernen sollten. Wenn Sie jedoch feststellen, dass die Spalte IDENTITY nicht erforderlich ist, entfernen Sie sie, um die Einfügeleistung zu verbessern.

5. Indizes oder Einschränkungen deaktivieren

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 Clusterschlüssel IDENTITY erhalten Sie eine minimale Protokollierung für alle neuen 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 ROWS_PER_BATCH Tuning kam zu demselben Konzept.

Zusammenfassend lässt sich sagen, dass Sie wahrscheinlich nicht viel tun können, um Ihren BULK INSERT Zu optimieren. 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 das folgende sehr einfache 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.

14
Joe Obbish

Ich werde mit der Beantwortung dieser Frage beginnen, mit der Absicht, diese Antwort kontinuierlich zu aktualisieren, während ich eine Wissensbasis mit Tricks aufbaue. Hoffentlich stoßen andere darauf und helfen mir dabei, mein eigenes Wissen zu verbessern.

  1. Gut Check: Führt Ihre Firewall eine Stateful Deep Packet Inspection durch? Sie werden im Internet nicht viel darüber finden, aber wenn Ihre Bulk-Inserts etwa 10-mal langsamer sind als sie sein sollten, haben Sie wahrscheinlich eine Security Appliance, die Deep Packet Inspection Level 3-7 durchführt und nach "Generic SQL Injection Prevention" sucht ".

  2. Messen Sie die Größe der Daten, die Sie in großen Mengen einfügen möchten, in Bytes pro Stapel. Überprüfen Sie auch, ob Sie LOB-Daten speichern, da dies ein separater Vorgang zum Abrufen und Schreiben von Seiten ist.

    Mehrere Gründe, warum Sie dies so tun sollten:

    ein. In AWS werden Elastic Block Storage-IOPS in Bytes und nicht in Zeilen unterteilt.

    1. Unter Amazon EBS Volume-Leistung unter Linux-Instanzen "E/A-Eigenschaften und Überwachung finden Sie eine Erläuterung der EBS IOPS-Einheit
    2. Insbesondere haben General Purpose SSD (gp2) -Volumes das Konzept "E/A-Credits und Burst-Leistung", und es ist üblich, dass bei starker ETL-Verarbeitung Burst-Balance-Credits aufgebraucht werden. Ihre Burst-Dauer wird in Bytes gemessen, nicht in SQL Server-Zeilen :)

    b. Während die meisten Bibliotheken oder Whitepapers anhand der Anzahl der Zeilen testen, ist es tatsächlich die Anzahl der Seiten, die in diese Angelegenheit geschrieben werden können. Um dies zu berechnen, müssen Sie wissen, wie viele Bytes pro Zeile und Ihre Seitengröße (normalerweise 8 KB) , aber überprüfen Sie immer, ob Sie das System von jemand anderem geerbt haben.)

    SELECT *
    FROM 
    sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID(N'YourTable'), NULL, NULL, 'DETAILED')
    

    Achten Sie auf avg_record_size_in_bytes und page_count.

    c. Wie Paul White in https://sqlperformance.com/2019/05/sql-performance/minimal-logging-insert-select-heap erklärt: "So aktivieren Sie eine minimale Protokollierung mit INSERT...SELECT, SQL Server muss mehr als 250 Zeilen mit einer Gesamtgröße von mindestens einer Ausdehnung (8 Seiten) erwarten. "

  3. Wenn Sie Indizes mit Prüfbeschränkungen oder eindeutigen Einschränkungen haben, verwenden Sie SET STATISTICS IO ON und SET STATISTICS TIME ON (oder SQL Server Profiler oder SQL Server Extended Events), um Informationen zu erfassen, z. B. ob Ihre Masseneinfügung welche enthält Leseoperationen. Lesevorgänge sind darauf zurückzuführen, dass das SQL Server-Datenbankmodul sicherstellt, dass die Integritätsbeschränkungen erfüllt werden.

  4. Versuchen Sie, eine Testdatenbank zu erstellen, in der PRIMARY FILEGROUP auf einem Laufwerk RAM) gemountet ist. Dies sollte etwas schneller als SSD sein, aber auch alle Fragen darüber, ob Ihr RAID-Controller vorhanden ist, beseitigen Möglicherweise sollte dies zu einem zusätzlichen Aufwand führen. Im Jahr 2018 sollte dies nicht der Fall sein. Wenn Sie jedoch mehrere differenzielle Baselines wie diese erstellen, erhalten Sie eine allgemeine Vorstellung davon, wie viel Aufwand Ihre Hardware hinzufügt.

  5. Legen Sie die Quelldatei auch auf ein Laufwerk RAM).

    Wenn Sie die Quelldatei auf ein Laufwerk RAM) legen, werden Konflikte ausgeschlossen, wenn Sie die Quelldatei von demselben Laufwerk lesen, auf dem sich die FILEGROUP Ihres Datenbankservers befindet.

  6. Stellen Sie sicher, dass Sie Ihre Festplatte mit 64-KB-Speicherbereichen formatiert haben.

  7. Verwenden Sie serBenchmark.com und vergleichen Sie Ihre SSD. Dieser Wille:

    1. Fügen Sie anderen Leistungsliebhabern mehr Wissen darüber hinzu, welche Leistung von einem Gerät zu erwarten ist
    2. Helfen Sie dabei, herauszufinden, ob die Leistung Ihres Laufwerks schlechter ist als die von Peers mit genau demselben Laufwerk
    3. Helfen Sie dabei, herauszufinden, ob die Leistung Ihres Laufwerks andere Laufwerke derselben Kategorie (SSD, HDD usw.) unterbietet.)
  8. Wenn Sie "INSERT BULK" von C # über Entity Framework Extensions aufrufen, stellen Sie sicher, dass Sie zuerst die JIT "aufwärmen" und die ersten Ergebnisse "wegwerfen".

  9. Versuchen Sie, Leistungsindikatoren für Ihr Programm zu erstellen. Mit .NET können Sie Benchmark.NET verwenden und automatisch eine Reihe grundlegender Metriken profilieren. Sie können dann Ihre Profiler-Versuche mit der Open Source-Community teilen und prüfen, ob Benutzer mit unterschiedlicher Hardware dieselben Metriken melden (z. B. aus meinem früheren Punkt über die Verwendung von UserBenchmark.com zum Vergleichen).

  10. Versuchen Sie, Named Pipes zu verwenden und als localhost auszuführen.

  11. Wenn Sie auf SQL Server abzielen und .NET Core verwenden, sollten Sie ein Linux mit SQL Server Std Edition starten - dies kostet selbst bei seriöser Hardware weniger als einen Dollar pro Stunde. Der Hauptvorteil beim Ausprobieren desselben Codes mit derselben Hardware und einem anderen Betriebssystem besteht darin, festzustellen, ob der TCP/IP-Stack des Betriebssystemkerns Probleme verursacht.

  12. Verwenden Sie die SQL Server-Diagnoseabfragen von Glen Barry, um die Laufwerkslatenz für das Laufwerk zu messen, auf dem die FILEGROUP Ihrer Datenbanktabelle gespeichert ist.

    ein. Stellen Sie sicher, dass Sie vor Ihrem Test und nach Ihrem Test messen. Das "vor Ihrem Test" sagt Ihnen nur, ob Sie schreckliche IO Eigenschaften als Basis haben).

    b. Zum Messen "während Ihres Tests" müssen Sie wirklich PerfMon-Leistungsindikatoren verwenden.

    Warum? Weil die meisten Datenbankserver eine Art Network Attached Storage (NAS) verwenden. In der Cloud, in AWS, ist Elastic Block Storage genau das. Sie könnten an die IOPS Ihrer EBS-Volume/NAS-Lösung gebunden sein.

  13. Verwenden Sie ein Tool, um Wartestatistiken zu messen. Red Gate SQL Monitor , SolarWinds Database Performance Analyzer oder sogar Glen Barrys SQL Server-Diagnoseabfragen oder Paul Randals Wartestatistikabfrage .

    ein. Die häufigsten Wartetypen sind wahrscheinlich Speicher/CPU, WRITELOG, PAGEIOLATCH_EX und ASYNC_NETWORK_IO .

    b. Wenn Sie Verfügbarkeitsgruppen ausführen, können zusätzliche Wartezeiten auftreten.

  14. Messen Sie die Auswirkungen mehrerer gleichzeitiger INSERT BULK Befehle mit deaktiviertem TABLOCK (TABLOCK erzwingt wahrscheinlich die Serialisierung von INSERT BULK-Befehlen). Ihr Engpass könnte darauf warten, dass ein INSERT BULK abgeschlossen wird. Sie sollten versuchen, so viele dieser Aufgaben in die Warteschlange zu stellen, wie das physische Datenmodell Ihres Datenbankservers verarbeiten kann.

  15. Erwägen Sie, Ihre Tabelle zu partitionieren. Als besonderes Beispiel: Wenn Ihre Datenbanktabelle nur anhängbar ist, schlug Andrew Novick vor, einen "HEUTE" FILEGROUP zu erstellen und in mindestens zwei Dateigruppen zu partitionieren, TODAY und BEFORE_TODAY. Auf diese Weise können Sie, wenn Ihre INSERT BULK -Daten nur Daten für heute sind, nach einem CreatedOn-Feld filtern, um alle Einfügungen zu zwingen, einen einzelnen FILEGROUP zu treffen, und dadurch die Blockierung bei Verwendung von TABLOCK verringern. Diese Technik wird in einem Microsoft Whitepaper ausführlicher beschrieben: Partitionierte Tabellen- und Indexstrategien mit SQL Server 2008

  16. Wenn Sie Columnstore-Indizes verwenden, deaktivieren Sie TABLOCK und laden Sie Daten in 102.400 Zeilen Stapelgröße. Sie können dann alle Ihre Daten parallel direkt in Spaltenspeicher-Zeilengruppen laden. Dieser Vorschlag (und rational dokumentiert) stammt aus Microsoft Columnstore-Indizes - Anleitung zum Laden von Daten :

    Beim Massenladen sind folgende Leistungsoptimierungen integriert:

    Parallele Ladevorgänge: Sie können mehrere gleichzeitige Massenladevorgänge (bcp oder Masseneinfügung) ausführen, die jeweils eine separate Datendatei laden. Im Gegensatz zum Massenladen von Rowstores in SQL Server müssen Sie TABLOCK nicht angeben, da jeder Massenimport-Thread Daten ausschließlich in separate Zeilengruppen (komprimierte oder Delta-Zeilengruppen) mit exklusiver Sperre lädt. Wenn Sie TABLOCK verwenden, wird die Tabelle exklusiv gesperrt, und Sie können keine Daten parallel importieren.

    Minimale Protokollierung: Eine Massenlast verwendet eine minimale Protokollierung von Daten, die direkt an komprimierte Zeilengruppen gesendet werden. Alle Daten, die an eine Delta-Zeilengruppe gesendet werden, werden vollständig protokolliert. Dies schließt alle Stapelgrößen ein, die weniger als 102.400 Zeilen betragen. Beim Massenladen besteht das Ziel jedoch darin, dass die meisten Daten Delta-Zeilengruppen umgehen.

    Sperroptimierung: Beim Laden in eine komprimierte Zeilengruppe wird die X-Sperre für die Zeilengruppe aktiviert. Beim Massenladen in eine Delta-Zeilengruppe wird jedoch eine X-Sperre für die Zeilengruppe erworben, SQL Server sperrt jedoch weiterhin die Sperren PAGE/EXTENT, da die X-Zeilengruppensperre nicht Teil der Sperrhierarchie ist.

  17. Ab SQL Server 2016 Trace-Flag 610 muss nicht mehr aktiviert werden, um sich nur minimal in der indizierten Tabelle anzumelden . Zitiert Microsoft-Ingenieur Parikshit Savjani ( Hervorhebung meiner ):

    Eines der Entwurfsziele von SQL Server 2016 war es, die Leistung und Skalierbarkeit der Engine sofort zu verbessern, damit sie schneller ausgeführt werden kann, ohne dass Knöpfe oder Trace-Flags für Kunden erforderlich sind. Als Teil dieser Verbesserungen bestand eine der im SQL Server-Engine-Code vorgenommenen Verbesserungen darin, den Massenladekontext (auch als schnelle Einfügungen oder Schnellladekontext bezeichnet) und standardmäßig die minimale Protokollierung zu aktivieren, wenn Durchführen von Massenladevorgängen für Datenbanken mit einem einfachen oder massenprotokollierten Wiederherstellungsmodell. Wenn Sie mit minimaler Protokollierung nicht vertraut sind, würde ich dringend empfehlen, diesen Blog-Beitrag von Sunil Agrawal zu lesen, in dem er erklärt, wie minimale Protokollierung funktioniert in SQL Server. Damit Masseneinsätze nur minimal protokolliert werden können, müssen die hier dokumentierten Voraussetzungen erfüllt sein.

    Im Rahmen dieser Verbesserungen in SQL Server 2016 müssen Sie das Ablaufverfolgungsflag 610 nicht mehr aktivieren, um sich nur minimal in der indizierten Tabelle anzumelden verbindet einige der anderen Trace-Flags (1118, 1117, 1236, 8048), um Teil der Geschichte zu werden. Wenn in SQL Server 2016 beim Massenladevorgang eine neue Seite zugewiesen wird, werden alle Zeilen, die diese neue Seite nacheinander füllen, minimal protokolliert, wenn alle anderen zuvor beschriebenen Voraussetzungen für eine minimale Protokollierung erfüllt sind. Zeilen, die in vorhandene Seiten eingefügt wurden (keine neue Seitenzuordnung), um die Indexreihenfolge beizubehalten, werden weiterhin vollständig protokolliert, ebenso wie Zeilen, die aufgrund von Seitenteilungen während des Ladens verschoben werden. Es ist auch wichtig, dass ALLOW_PAGE_LOCKS für Indizes (die standardmäßig aktiviert sind) aktiviert ist, damit ein minimaler Protokollierungsvorgang funktioniert, da Seiten-Sperren während der Zuweisung erfasst werden und daher nur Seiten- oder Extent-Zuweisungen protokolliert werden.

  18. Wenn Sie SqlBulkCopy in C # oder EntityFramework.Extensions verwenden (das SqlBulkCopy unter der Haube verwendet), überprüfen Sie Ihre Build-Konfiguration. Führen Sie Ihre Tests im Release-Modus aus? Ist die Zielarchitektur auf Beliebige CPU/x64/x86 eingestellt?

  19. Verwenden Sie sp_who2, um festzustellen, ob die Transaktion INSERT BULK SUSPENDED ist. Es könnte SUSPENDED sein, weil es von einem anderen Spid blockiert wird. Lesen Sie Minimieren der SQL Server-Blockierung . Sie können auch Adam Machanics sp_WhoIsActive verwenden, aber sp_who2 gibt Ihnen die grundlegenden Informationen, die Sie benötigen.

  20. Möglicherweise haben Sie nur fehlerhafte Festplatten-E/A. Wenn Sie eine Masseneinfügung durchführen und Ihre Festplattenauslastung nicht 100% erreicht und bei etwa 2% stecken bleibt, haben Sie wahrscheinlich entweder eine schlechte Firmware oder ein defektes E/A-Gerät. (Dies ist einem meiner Kollegen passiert.) Verwenden Sie [SSD UserBenchmark], um die Hardwareleistung mit anderen zu vergleichen, insbesondere wenn Sie die Langsamkeit auf Ihrem lokalen Entwicklungscomputer replizieren können. (Ich habe dies als letztes in die Liste aufgenommen, da die meisten Unternehmen Entwicklern aufgrund des IP-Risikos nicht erlauben, Datenbanken auf ihrem lokalen Computer auszuführen.)

  21. Wenn Ihre Tabelle eine Komprimierung verwendet, können Sie versuchen, mehrere Sitzungen auszuführen. Beginnen Sie in jeder Sitzung mit nter Verwendung einer vorhandenen Transaktion und führen Sie diese vor dem Befehl SqlBulkCopy aus:

    ALTER SERVER CONFIGURATION SET PROCESS AFFINITY CPU = AUTO;

  22. Für das kontinuierliche Laden ein Ideenstrom, der zuerst in einem Microsoft-Whitepaper beschrieben wurde: Partitionierte Tabellen- und Indexstrategien mit SQL Server 2008 :

    Kontinuierliches Laden

    In einem OLTP -Szenario) werden möglicherweise ständig neue Daten eingehen. Wenn Benutzer auch die neueste Partition abfragen, kann das kontinuierliche Einfügen von Daten zum Blockieren führen: Benutzerabfragen blockieren möglicherweise die Einfügungen und in ähnlicher Weise Einfügungen können die Benutzerabfragen blockieren.

    Konflikte in der Ladetabelle oder Partition können durch Verwendung der Snapshot-Isolation reduziert werden, insbesondere durch die Isolationsstufe READ COMMITTED SNAPSHOT. Unter READ COMMITTED SNAPSHOT Isolation verursachen Einfügungen in eine Tabelle keine Aktivität im tempdb Versionsspeicher, daher der Der Aufwand für tempdb ist für Einfügungen minimal, aber Benutzerabfragen auf derselben Partition nehmen keine gemeinsam genutzten Sperren auf.

    In anderen Fällen, wenn Daten kontinuierlich mit einer hohen Rate in eine partitionierte Tabelle eingefügt werden, können Sie die Daten möglicherweise noch für kurze Zeit in Staging-Tabellen bereitstellen und diese Daten dann wiederholt in die neueste Partition einfügen, bis das Fenster für angezeigt wird Die aktuelle Partition wird übergeben und die Daten werden dann in die nächste Partition eingefügt. Angenommen, Sie haben zwei Staging-Tabellen, die abwechselnd Daten im Wert von jeweils 30 Sekunden empfangen: eine Tabelle für die erste halbe Minute, die zweite Tabelle für die zweite halbe Minute. Eine gespeicherte Prozedur zum Einfügen bestimmt, in welcher halben Minute sich die aktuelle Einfügung befindet, und fügt sie dann in die erste Staging-Tabelle ein. Wenn 30 Sekunden abgelaufen sind, bestimmt das Einfügeverfahren, dass es in die zweite Staging-Tabelle eingefügt werden muss. Eine andere gespeicherte Prozedur lädt dann die Daten aus der ersten Staging-Tabelle in die neueste Partition der Tabelle und schneidet dann die erste Staging-Tabelle ab. Nach weiteren 30 Sekunden fügt dieselbe gespeicherte Prozedur die Daten aus der zweiten gespeicherten Prozedur ein und legt sie in der aktuellen Partition ab. Anschließend wird die zweite Staging-Tabelle abgeschnitten.

  23. Microsoft CAT-Team The Data Loading Performance Guide

  24. Stellen Sie sicher, dass Ihre Statistiken auf dem neuesten Stand sind. Verwenden Sie FULLSCAN, wenn Sie nach jedem Indexaufbau können.

  25. SAN-Leistungsoptimierung mit SQLIO und stellen Sie außerdem sicher, dass Ihre Festplattenpartitionen ausgerichtet sind, wenn Sie mechanische Festplatten verwenden. Siehe Microsoft Best Practices für die Ausrichtung von Festplattenpartitionen .

  26. COLUMNSTOREINSERT/UPDATE Leistung

12
John Zabroski

Bei den Lesevorgängen handelt es sich wahrscheinlich um die eindeutigen & FK-Einschränkungen, die während des Einfügens überprüft werden. Sie können eine Geschwindigkeitsverbesserung erzielen, wenn Sie sie während des Einfügens deaktivieren/löschen und anschließend aktivieren/neu erstellen können. Sie müssen testen, ob dies insgesamt langsamer ist, als wenn Sie sie aktiv halten. Dies ist möglicherweise auch keine gute Idee, wenn andere Prozesse gleichzeitig in dieselbe Tabelle schreiben. - Gareth Lyons

Gemäß den Fragen und Antworten Fremdschlüssel werden nach dem Masseneinfügen nicht mehr vertrauenswürdig werden FK-Einschränkungen nach einer BULK INSERT Ohne CHECK_CONSTRAINTS - Option nicht mehr vertrauenswürdig (mein Fall, als ich mit nicht vertrauenswürdig endete Einschränkungen). Es ist nicht klar, aber es wäre nicht sinnvoll, sie zu überprüfen und sie dennoch nicht vertrauenswürdig zu machen. PK und UNIQUE werden jedoch weiterhin überprüft (siehe BULK INSERT (Transact-SQL) ). - Alexei

2
user126897