Sehr langsamer Einfügeprozess mit Linq zu Sql

8

Ich füge eine große Anzahl von Datensätzen mit LinqToSql von C # in SqlServer 2008 Express DB ein. Es sieht so aus, als wäre die Einfügung sehr langsam. Im Folgenden ist das Code-Snippet.

%Vor%

Mache ich etwas falsch? Oder die Verwendung von Linq zum Einfügen einer großen Anzahl von Datensätzen ist eine schlechte Wahl?

Update: Danke für alle Antworten. @ p.campbell: Entschuldigung für die Anzahl der Datensätze, es war ein Tippfehler, tatsächlich ist es um 100000. Datensätze reichen auch bis 200k.

Wie bei allen Vorschlägen habe ich diese Operation in Teile verschoben (auch eine Änderung der Anforderungen und Designentscheidungen) und Daten in kleinen Stücken abgerufen und sie in die Datenbank eingefügt, wann und wie sie kommt. Ich habe diese InsertData () -Methode in Thread-Operation und jetzt mit SmartThreadPool zum Erstellen eines Pools von 25 Threads für die gleiche Operation. In diesem Szenario füge ich jeweils nur 100 Datensätze ein. Jetzt, als ich dies mit Linq oder SQL-Abfrage versuchte, machte es keinen Unterschied in Bezug auf die Zeit genommen.

Gemäß meiner Anforderung wird diese Operation jede Stunde ausgeführt und ruft Datensätze für ungefähr 4k-6k Benutzer ab. So, jetzt bin ich Pooling alle Benutzerdaten (Abrufen und Einfügen in DB) Operation als eine Aufgabe und zugeordnet zu einem Thread. Jetzt dauert dieser gesamte Prozess ungefähr 45 Minuten für ungefähr 250.000 Datensätze.

Gibt es einen besseren Weg, diese Art von Aufgabe zu erledigen? Oder kann mir jemand vorschlagen, wie ich diesen Prozess verbessern kann?

    
JPReddy 20.09.2010, 11:29
quelle

4 Antworten

11

Zum Einfügen einer großen Datenmenge in SQL in einem

Linq oder SqlCommand, sind nicht für das Massenkopieren von Daten in SQL ausgelegt.

Sie können die Klasse SqlBulkCopy verwenden, die verwalteten Zugriff auf das bcp-Dienstprogramm zum Massenladen von Daten in Sql von so ziemlich jeder Datenquelle.

  

Die SqlBulkCopy-Klasse kann verwendet werden, um Daten nur in SQL Server-Tabellen zu schreiben. Die Datenquelle ist jedoch nicht auf SQL Server beschränkt. Jede Datenquelle kann verwendet werden, solange die Daten in eine DataTable-Instanz geladen oder mit einer IDataReader-Instanz gelesen werden können.

Leistungsvergleich

SqlBulkCopy ist mit Abstand am schnellsten, auch wenn Daten aus einer einfachen CSV-Datei geladen werden.

Linq generiert nur eine Ladung von Insert -Anweisungen in SQL und sendet sie an Ihren SQL Server. Dies ist nicht anders als bei Ad-hoc-Abfragen mit SqlCommand . Die Leistung von SqlCommand gegenüber Linq ist praktisch identisch.

Der Beweis

(SQL Express 2008, .Net 4.0)

SqlBulkCopy

Verwenden von SqlBulkCopy zum Laden von 100000 Zeilen aus einer CSV-Datei (einschließlich Laden der Daten)

%Vor%

SqlCommand

%Vor%

LinqToSql

%Vor%

Ergebnisse

%Vor%     
badbod99 20.09.2010, 12:11
quelle
3

Wenn Sie große Datensätze einfügen, können Sie versuchen, BULK INSERT zu verwenden.

Nach meinem Wissen gibt es in Linq to SQL kein Äquivalent zur Masseneinfügung.

    
anishMarokey 20.09.2010 11:32
quelle
3

Sie haben die SubmitChanges() einmal aufgerufen, was gut ist. Dies bedeutet, dass nur eine Verbindung und Transaktion verwendet werden.

Erwägen Sie, Ihren Code so zu refactorisieren, dass stattdessen InsertAllOnSubmit() verwendet wird.

%Vor%

Die INSERT-Anweisungen werden wie vorher eins nach dem anderen gesendet, aber vielleicht ist dies besser lesbar?

Einige andere Dinge zu fragen / zu beachten:

  • Was ist der Status der Indizes in der Zieltabelle? Zu viele werden die Schreibvorgänge verlangsamen. * Ist die Datenbank im einfachen oder vollständigen Wiederherstellungsmodell?
  • Erfassen Sie die SQL-Anweisungen, die über die Leitung gehen. Wiederholen Sie diese Anweisungen in einer Ad-hoc-Abfrage für Ihre SQL Server-Datenbank. Mir ist klar, dass Sie SQL Express verwenden und wahrscheinlich keinen SQL Profiler haben. Verwenden Sie context.Log = Console.Out; , um Ihre LINQ To SQL-Anweisungen an die Konsole auszugeben . Bevorzugen Sie jedoch SQL Profiler für die Bequemlichkeit.
  • Führen die erfassten SQL-Anweisungen dasselbe wie Ihr Clientcode aus? Wenn ja, dann ist das Perf-Problem auf der Datenbankseite.
p.campbell 20.09.2010 11:33
quelle
1

Hier finden Sie einen schönen Überblick darüber, wie Sie Ihrer Anwendung eine Bulk-Insert-Klasse hinzufügen, was die Performance beim Einfügen von Datensätzen mit LINQ enorm verbessert.

(Der gesamte Quellcode wird zur Verfügung gestellt und ist bereit, zu Ihrer eigenen Anwendung hinzugefügt zu werden.)

Ссылка

Sie müssten lediglich drei Änderungen an Ihrem Code vornehmen und in der bereitgestellten Klasse verknüpfen. Viel Glück!

    
Mike Gledhill 30.11.2011 16:09
quelle

Tags und Links