Wie kann sichergestellt werden, dass das gleichzeitige EINFÜGEN und AUSWÄHLEN in einer Tabelle keinen Deadlock verursacht?

7

Ich habe die folgende Tabelle in meiner SQL Server 2008-Datenbank:

CREATE TABLE [dbo].[SomeTable]
(
   [Id] [bigint] IDENTITY(1,1) NOT NULL,
   [Column1] [varchar](30) NOT NULL,
   [Column2] [varchar](30) NOT NULL,
   [Column3]  [varchar](50) NOT NULL,
   CONSTRAINT [PK_SomeTable] PRIMARY KEY CLUSTERED 
   (
  [Id] ASC
   )
 )

Ein Prozess fügt Daten in diese Tabelle ein, ein anderer Prozess liest alle Daten aus dieser Tabelle. Beide Prozesse arbeiten gleichzeitig.

one process:
INSERT INTO dbo.SomeTable VALUES ('col1', 'col2', 'col3')

another process:
SELECT Id, Column1, Column2, Column3 FROM dbo.SomeTable

Ich sehe, dass die zweite Abfrage einen vollständigen Tabellenscan durchführt, aber ich muss alle Daten aus dieser Tabelle zur weiteren Verarbeitung abrufen (es wird keine sehr große Tabelle sein, da sie regelmäßig bereinigt wird. Sie enthält 1K-2K-Zeilen ).

Gibt es eine Möglichkeit, um sicherzustellen, dass bei diesen beiden Abfragen niemals Deadlocks auftreten?

Sergey Smelov
quelle
5
Worst-Case-Szenario: Sie erhalten eine schmutzige Lesung. Deadlocks sollten nicht passieren.
Sie sind beide unterschiedliche Prozesse, aber beide sprechen mit demselben SQL Server, bei dem es sich um einen einzelnen Prozess handelt, der jedoch über mehrere Threads verfügt. SQL Server übernimmt das Sperren.
Shiplu Mokaddim
Warum postest du keine Antwort?
Sergey Smelov
@ SergeySmelov: weil diese Antwort Ihre Frage nicht beantwortet und hier irrelevant ist
gbn
@alex - Wie würde bei fehlerhafter Sperrung ein Dirty Read auftreten? Sie müssten angeben, dass Sie mit Dirty Reads (auch bekannt als NOLOCK) einverstanden sind.
RQDQ

Antworten:

7

Deadlocks treten bei der Standard-Sperrstrategie immer irgendwann auf. In Ihrem gegebenen Szenario ist dies jedoch aufgrund des geraden Tabellenscans unwahrscheinlich.

Es ist jedoch wahrscheinlicher, wenn Sie mehrere INSERTs und SELECTs gleichzeitig haben.

Die Verwendung von NOLOCK bedeutet Dirty Reads und ist keine bewährte Methode. Jeder scheint sie jedoch vorzuschlagen ...

Die Alternative besteht darin, Snapshot-Isolationsmodi zu verwenden: SELECT liest die zuletzt festgeschriebenen Daten, anstatt vom INSERT blockiert zu werden.

gbn
quelle
Ja, ich kann mehrere INSERTS und SELECTS gleichzeitig ausführen. Ich habe gehört, dass die Snapshot-Isolation die Leistung beeinträchtigen könnte. Gibt es andere Möglichkeiten, Deadlocks zu minimieren? Vielleicht Deadlock Try-Catch-Handler hinzufügen?
Sergey Smelov
Und was soll ich tun, um mögliche Deadlocks zu erkennen? Hochlasttests für die Datenbank durchführen?
Sergey Smelov
@SergeySmelov: Es ist schwierig, Deadlocks zu generieren, es sei denn, Sie haben exklusive Sperren (diesen Block). Ausgewählte sind nicht exklusiv, sondern werden geteilt. Ausnahmebehandlung ist auch teuer ...
gbn
@SergeySmelov, um Deadlocks wie den zu reproduzieren, auf den Sie stoßen, verwenden Sie die Skripte in diesem Beitrag: "Reproduzieren von Deadlocks mit nur einer Tabelle"
AK
@AlexKuznetsov Wie viele Iterationen reichen aus, um sicherzustellen, dass niemals ein Deadlock auftritt? 10000? 1000000?
Sergey Smelov
1

Wenn Sie mit Dirty Reads leben können, können Sie den Abfragehinweis für die NOLOCK- Tabelle angeben . Wenn die einzigen Operationen, die ausgeführt werden, Einfügungen sind und Sie nicht mit Daten in anderen Tabellen verknüpfen, ist dies möglicherweise eine praktikable Lösung.

Bitte beachten Sie, dass der NOLOCK-Hinweis in vielen Szenarien überbeansprucht und missbraucht wurde. Beachten Sie auch, dass es sich um einen Hinweis und nicht um eine Anweisung handelt. Mit anderen Worten, ich glaube nicht, dass es garantiert ist, das Sperren in allen Szenarien zu verhindern.

RQDQ
quelle
Denken Sie, dass diese beiden Abfragen Deadlock-frei sind?
Sergey Smelov
1

SELECT COUNT (*) FROM Student WITH (NOLOCK)

Es kann jedoch zu anderen Datenkonsistenzproblemen führen, wenn wir es in einer komplexen Umgebung verwenden. Zum Beispiel, wenn Einfügen der Teil der Transaktion ist und Sie mit select auslesen und die Transaktion fehlschlägt. In diesem Szenario wird Ihre Einfügeanweisung möglicherweise zurückgesetzt und das ausgewählte Ergebnis ist beschädigt. Wenn Sie es also verwenden möchten, stellen Sie sicher, dass Einfügen nicht Teil der Transaktion ist. Zum besseren Verständnis können Sie auf diese Seite verweisen

http://www.techrepublic.com/article/using-nolock-and-readpast-table-hints-in-sql-server/6185492


quelle