Ich habe einen Prozess, der mehrere Threads ausführt.
Process verfügt über eine Thread-sichere Sammlung von zu verarbeitenden Elementen.
Jeder Thread verarbeitet Elemente aus der Sammlung in einer Schleife.
Jedes Element in der Liste wird vom Thread an eine gespeicherte Prozedur gesendet, um Daten in 3 Tabellen in einer Transaktion (in sql) einzufügen. Wenn eine Einfügung fehlschlägt, schlagen alle drei fehl. Beachten Sie, dass der Transaktionsumfang pro Element ist.
Die Einfügungen sind ziemlich einfach, indem Sie nur eine Zeile (mit Fremdschlüsseln) in jede Tabelle einfügen, mit identischen Seeds. Es gibt kein Lesen, nur einfügen und dann zum nächsten Element weitergehen.
Wenn ich mehrere Threads habe, die versuchen, ihre eigenen Elemente zu verarbeiten, die jeweils versuchen, in denselben Satz von Tabellen einzufügen, werden dadurch Deadlocks, Timeouts oder andere Probleme aufgrund von Transaktionssperren entstehen?
Ich weiß, dass ich pro Thread eine db-Verbindung verwenden muss. Ich kümmere mich hauptsächlich um die Sperrstufen von Tabellen in jeder Transaktion. Wenn ein Thread Zeilen in die 3 Tabellen einfügt, müssen die anderen Threads warten? Es gibt keine Abhängigkeit von Zeilen pro Tabelle, außer dass die automatische Identifizierung inkrementiert werden muss. Wenn es eine Sperre auf Tabellenebene ist, um die Identität zu erhöhen, dann nehme ich an, dass andere Threads warten müssen. Die Einsätze können manchmal schnell sein oder nicht. Wenn es warten muss, macht es Sinn Multithreading zu machen?
Das Ziel für Multithreading ist die Beschleunigung der Verarbeitung von Elementen.
Bitte teilen Sie Ihre Erfahrung.
PS: Identity Seed ist keine GUID.
In SQL Server blockieren mehrere Einfügungen in eine einzelne Tabelle normalerweise nicht gegenseitig. Der IDENTITY-Erzeugungsmechanismus ist stark parallel, so dass der Zugriff nicht serialisiert wird. Einfügungen dürfen sich gegenseitig blockieren, wenn sie den gleichen Schlüssel in einen eindeutigen Index einfügen (einer von ihnen wird auch eine doppelte Schlüsselverletzung erleiden, wenn beide versuchen, zu committen). Sie haben auch eine Wahrscheinlichkeit Spiel, weil Schlüssel gehasht werden, aber es kommt nur ins Spiel, in großen Transaktionen finden Sie unter . Wenn die Transaktion in mehrere Tabellen fügt außerdem sollte es keine Konflikte, solange wieder eingefügt die Tasten disjunkt sind (dies geschieht natürlich, wenn die Einsätze Master-Kind-Kind sind).
Das Vorhandensein sekundärer Indizes und speziell der Fremdschlüssel-Constraints kann dazu führen, dass Blockierungen und mögliche Deadlocks eingeführt werden. Ohne eine genaue Schemadefinition ist es unmöglich zu sagen, ob Sie für Deadlocks anfällig sind oder nicht. Jede andere Arbeitslast (Berichte, Lesevorgänge, Wartung) trägt ebenfalls zu den Konfliktproblemen bei und kann Blockierungen und Deadlocks verursachen.
Wirklich wirklich wirklich High-End-Installationen (die Art, die für die Beratung in Foren fragen Sie nicht brauchen ...) kann leiden unter Einsatz Hot Spot Symptome finden Sie unter Resolving PAGELATCH Conten auf Hoch Concurrent INSERT Workloads
Übrigens ist das Ausführen von INSERTs aus mehreren Threads sehr selten die richtige Antwort zum Erhöhen des Lastdurchsatzes. Siehe Laden der Daten -Leistungshandbuch für gute Ratschläge, wie man Lösen Sie das Problem . Und noch ein letzter Hinweis: Mehrfache Threads sind auch selten die Antwort darauf, irgendein Programm schneller zu machen. Async-Programmierung ist fast immer die richtige Antwort. Siehe AsynchronousProcessing
und BeginExecuteNonQuery
.
Als Randnotiz:
nur eine Zeile einfügen (Fremdschlüssel bezogen) in jede Tabelle, ... Es gibt kein Lesen,
Diese Aussage widerspricht sich tatsächlich. Fremdschlüssel impliziert Lesevorgänge, da sie während Schreibvorgängen überprüft werden müssen.
Was macht Sie denken, es muss eine Sperre auf Tabellenebene sein, wenn es eine Identität gibt. Ich sehe das in keiner der Dokumentation und ich habe gerade eine Einfügung mit (rowlock) auf einer Tabelle mit einer Identitätsspalte getestet und es funktioniert.
Um das Sperren zu minimieren, nehmen Sie eine Zeilensperre. Bei allen gespeicherten Prozeduren werden die Tabellen in der gleichen Reihenfolge aktualisiert.
Sie haben Einsätze in drei Tabellen, die jeweils bis zu 10 Sekunden dauern? Ich habe einige Einfügungen in Transaktionen, die mehrere Tabellen treffen (einige von ihnen groß) und 100 / Sekunde bekommen.
Überprüfen Sie Ihr Tabellendesign und die Tasten. Wenn Sie eine gruppierte PK auswählen können, die die Reihenfolge Ihrer Einfügung darstellt, und wenn Sie vor dem Einfügen sortieren können, wird es einen großen Unterschied machen. Überprüfen Sie, ob weitere Indizes erforderlich sind. Wenn Sie andere Indizes haben müssen, dann überwachen Sie die Fragmentierung und Defragmentierung.
Related, aber nicht das Gleiche. Ich habe einen Dataloader, der einige Daten analysieren und dann Millionen von Zeilen pro Nacht laden muss, aber nicht in einer Transaktion. Es wurde bei 4 parallelen Prozessen optimiert, beginnend mit leeren Tabellen, aber das Problem war nach zwei Stunden Ladedurchsatz aufgrund der Fragmentierung um einen Faktor 10 geringer. Ich habe die Tabellen neu gestaltet, sodass der PK-Clustered-Index in der Einfügereihenfolge war. Hat einen anderen Index gelöscht, der nicht mindestens 50% Auswahl-Bump ergeben hat. Beim nächtlichen Einfügen zuerst die Indizes löschen (deaktivieren) und nur zwei Threads verwenden. Ein Thread zum Parsen und ein Thread zum Einfügen. Dann erstelle ich den Index am Ende der Ladung neu. Got 100: 1 Verbesserung über 4 Threads hämmern die Indizes. Ja, Sie haben ein anderes Problem, aber überprüfen Sie Ihre Tabellen. Zu oft denke ich, dass Indizes für kleine ausgewählte Vorteile hinzugefügt werden, ohne den Treffer zum Einfügen und Aktualisieren zu berücksichtigen. Auch der Auswahlvorteil ist oft überbewertet, wenn Sie den Index erstellen und vergleichen und dieser neue Index keine Fragmentierung aufweist.
Heavy-Duty DBMS wie mssql sind im Allgemeinen sehr, sehr gut im Umgang mit Nebenläufigkeit. Was genau mit Ihren gleichzeitig ausgeführten Transaktionen passiert, hängt weitgehend von Ihrem TI-Level ( Ссылка ), die Sie einstellen können, wie Sie es für richtig halten, aber in diesem Szenario denke ich nicht, dass Sie sich um Deadlocks kümmern müssen.
Ob es sinnvoll ist oder nicht - es ist immer schwer zu erraten, ohne etwas über Ihr System zu wissen. Es ist nicht schwer es auszuprobieren, aber das kannst du selbst herausfinden. Wenn ich raten sollte, würde ich sagen, es wird dir nicht viel helfen, wenn alle deine Threads tun werden, Zeilen round-robin einzufügen.
Die anderen Threads warten trotzdem, Ihr PC kann wirklich nicht mehr Threads ausführen als die CPU-Kerne, die Sie in jedem Moment haben.
Sie haben geschrieben, dass Sie Multi-Threading verwenden möchten, um die Verarbeitung zu beschleunigen. Ich bin mir nicht sicher, ob das etwas ist, was man automatisch als gegeben / richtig nehmen kann. Der Grad der Parallelität und ihre Auswirkungen auf die Verarbeitungsgeschwindigkeit hängen von vielen Faktoren ab, die sehr prozessabhängig sind, z. B. ob ein IO beteiligt ist oder ob jeder Thread nur in der Speicherverarbeitung arbeiten soll. Das ist, denke ich, einer der Gründe, warum Microsoft die Task Scheduler in ihrem tpl Framework anbietet, und im Allgemeinen die Konkurenz in dieser Bibliothek als etwas behandelt, das zur Laufzeit gesetzt werden soll.
Ich denke, Ihre sicherste Wette besteht darin, Testabfragen / -prozesse auszuführen, um genau zu sehen, was passiert (obwohl es natürlich immer noch nicht 100% genau ist). Sie können auch die Funktionen optimistic concurrency von sql server lesen, die blockierungsfreie Arbeit ermöglichen ( Ich bin nicht sicher, wie es Identitätsspalten behandelt)
Tags und Links .net sql-server c# multithreading sql-server-2008