Wie untersucht man die Leistung einer BULK INSERT-Anweisung?

12

Ich bin hauptsächlich ein .NET-Entwickler, der Entity Framework ORM verwendet. Da ich jedoch die Verwendung des ORM nicht versagen möchte , 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 keinen SHOWPLAN zu produzieren scheint .

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 anderen Indizes definiert

Die Masseneinlage (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?

Alexei
quelle

Antworten:

14

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 ORDERArgument 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 IDENTITYSpalte als Clusterschlüssel verwenden, müssen Sie sich darüber keine Gedanken machen.

2. TABLOCKWenn möglich verwenden

Wenn Sie garantiert nur eine Sitzung haben, in der Daten in Ihre Tabelle eingefügt werden, können Sie das TABLOCKArgument 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 TABLOCKnicht 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 IDENTITYSpalte 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 IDENTITYSpalte aus dieser Tabelle entfernen sollten . Wenn Sie jedoch feststellen, dass die IDENTITYSpalte 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 IDENTITYClusterschlü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_BATCHStimmen 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.

Joe Obbish
quelle
12

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 Performance unter Linux-Instanzen »E / A-Eigenschaften und Überwachung finden Sie eine Erläuterung der EBS IOPS-Einheit
    2. Insbesondere SSP-Volumes (General Purpose SSD) verfügen über das Konzept "E / A-Credits und Burst-Leistung", und bei starker ETL-Verarbeitung werden häufig Burst-Balance-Credits aufgebraucht. 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 : "Um eine minimale Protokollierung mit zu ermöglichen INSERT...SELECT, muss SQL Server mehr als 250 Zeilen mit einer Gesamtgröße erwarten von mindestens einem Umfang (8 Seiten). "

  3. Wenn Sie Indizes mit Prüfeinschränkungen oder eindeutigen Einschränkungen haben, verwenden Sie SET STATISTICS IO ONund SET STATISTICS TIME ON(oder SQL Server Profiler oder SQL Server Extended Events), um Informationen zu erfassen, z. B. ob Ihre Masseneinfügung Lesevorgänge enthält. 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 PRIMARYFILEGROUP auf einem RAM-Laufwerk bereitgestellt ist. Dies sollte etwas schneller als SSD sein, aber auch alle Fragen beseitigen, ob Ihr RAID-Controller möglicherweise zusätzlichen Aufwand verursacht. Im Jahr 2018 sollte dies nicht der Fall sein. Wenn Sie jedoch mehrere unterschiedliche Basislinien wie diese erstellen, erhalten Sie eine allgemeine Vorstellung davon, wie viel Overhead Ihre Hardware hinzufügt.

  5. Legen Sie die Quelldatei auch auf einem RAM-Laufwerk ab.

    Wenn Sie die Quelldatei auf einem RAM-Laufwerk ablegen, 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 UserBenchmark.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 Kollegen mit genau demselben Laufwerk
    3. Helfen Sie 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 es werden automatisch einige grundlegende Metriken profiliert. 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 als Basis schreckliche E / A-Eigenschaften 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 die SQL Server-Diagnoseabfragen von Glen Barry oder die Wartestatistikabfrage von Paul Randal .

    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 BULKBefehle mit TABLOCKdeaktiviertem Befehl (TABLOCK erzwingt wahrscheinlich die Serialisierung von INSERT BULK-Befehlen). Ihr Engpass könnte darauf warten, dass ein INSERT BULKFehler behoben 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 zum Anhängen dient, schlug Andrew Novick vor, ein "HEUTE" zu erstellen FILEGROUPund in mindestens zwei Dateigruppen zu partitionieren, HEUTE und BEFORE_TODAY. Auf diese Weise können Sie, wenn Ihre INSERT BULKDaten nur Daten für heute sind, nach einem CreatedOn-Feld filtern, um zu erzwingen, dass alle Einfügungen einen einzigen Treffer erzielen FILEGROUP, und so die Blockierung bei der Verwendung verringern TABLOCK. Diese Technik wird in einem Microsoft Whitepaper: Partitionierte Tabellen- und Indexstrategien mit SQL Server 2008 ausführlicher beschrieben

  16. Wenn Sie Columnstore-Indizes verwenden, deaktivieren TABLOCKund 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 den Columnstore-Indizes von Microsoft - Anleitung zum Laden von Daten :

    Beim

    Massenladen sind folgende Leistungsoptimierungen integriert: Parallele Ladevorgänge: Sie können mehrere Massenladevorgänge gleichzeitig ausführen (bcp oder Masseneinfügung), die jeweils eine separate Datendatei laden. Im Gegensatz zum Massenladen von Rowstores in SQL Server müssen Sie keine Angaben machen, TABLOCKda jeder Massenimport-Thread Daten ausschließlich in separate Zeilengruppen (komprimierte oder Delta-Zeilengruppen) mit exklusiver Sperre lädt. Durch TABLOCKdie Verwendung wird eine exklusive Sperre für die Tabelle erzwungen, und Sie können keine Daten parallel importieren.

    Minimale Protokollierung:Eine Massenlast verwendet nur minimale Protokollierungsdaten, 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 muss das Ablaufverfolgungsflag 610 für eine minimale Anmeldung in der indizierten Tabelle nicht mehr aktiviert werden . Zitat des Microsoft-Ingenieurs Parikshit Savjani ( Schwerpunkt Mine ):

    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 Verbesserungen im SQL Server-Engine-Code darin, den Massenladekontext (auch als schnelle Einfügungen oder Schnellladekontext bezeichnet) und standardmäßig nur eine minimale Protokollierung zu aktivieren, wenn Massenladevorgänge für Datenbanken mit einfach oder ausgeführt werden Massenprotokolliertes Wiederherstellungsmodell. Wenn Sie mit minimaler Protokollierung nicht vertraut sind, würde ich Ihnen dringend empfehlen, diesen Blog-Beitrag von Sunil Agrawal zu lesen, in dem er erklärt, wie minimale Protokollierung in SQL Server funktioniert. 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 einer indizierten Tabelle anzumeldenund es verbindet einige der anderen Spurenflags (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 werden (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 INSERT BULK-Transaktion SUSPENDED ist. Es könnte SUSPENDED sein, weil es von einem anderen Spid blockiert wird. Lesen Sie, wie Sie die SQL Server-Blockierung minimieren . 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 der 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, Partitionierte Tabellen- und Indexstrategien mit SQL Server 2008 beschrieben wurde :

    Kontinuierliches Laden

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

    Konflikte auf der Ladetabelle oder Partition können durch Verwendung der Snapshot-Isolation, insbesondere der READ COMMITTED SNAPSHOTIsolationsstufe , reduziert werden . Im READ COMMITTED SNAPSHOTisolierten Zustand verursachen Einfügungen in eine Tabelle keine Aktivität im Tempdb- Versionsspeicher, sodass der Tempdb- Overhead für Einfügungen minimal ist, Benutzerabfragen auf derselben Partition jedoch keine gemeinsam genutzten Sperren übernehmen.

    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. Das Leistungshandbuch zum Laden von Daten des Microsoft CAT-Teams

  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 bei Verwendung mechanischer Festplatten sicher, dass Ihre Festplattenpartitionen ausgerichtet sind. Weitere Informationen finden Sie in den Best Practices für die Ausrichtung von Festplattenpartitionen von Microsoft .

  26. COLUMNSTORE INSERT/ UPDATELeistung

John Zabroski
quelle
2

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 werden Fremdschlüssel nach dem Masseneinfügen nicht mehr vertrauenswürdig , FK-Einschränkungen werden nach einer Option BULK INSERTohne CHECK_CONSTRAINTSOption nicht mehr vertrauenswürdig (mein Fall, als ich mit nicht vertrauenswürdigen Einschränkungen endete). 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

user126897
quelle