Frage

Wir sehen einige schädliche, aber seltene Deadlock-Bedingungen in der Stack Overflow SQL Server 2005-Datenbank.

Ich habe den Profiler angeschlossen und mit ein Trace-Profil eingerichtet Dieser ausgezeichnete Artikel zur Fehlerbehebung bei Deadlocks, und eine Reihe von Beispielen festgehalten.Das Seltsame ist das Das Deadlocking-Schreiben ist stets das gleiche:

UPDATE [dbo].[Posts]
SET [AnswerCount] = @p1, [LastActivityDate] = @p2, [LastActivityUserId] = @p3
WHERE [Id] = @p0

Die andere Deadlock-Anweisung variiert, ist aber normalerweise trivial und einfach lesen der Beitragstabelle.Dieser wird immer im Deadlock getötet.Hier ist ein Beispiel

SELECT
[t0].[Id], [t0].[PostTypeId], [t0].[Score], [t0].[Views], [t0].[AnswerCount], 
[t0].[AcceptedAnswerId], [t0].[IsLocked], [t0].[IsLockedEdit], [t0].[ParentId], 
[t0].[CurrentRevisionId], [t0].[FirstRevisionId], [t0].[LockedReason],
[t0].[LastActivityDate], [t0].[LastActivityUserId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[ParentId] = @p0

Um es ganz klar zu sagen: Wir sehen keine Schreib-/Schreib-Deadlocks, sondern Lese-/Schreib-Deadlocks.

Wir haben derzeit eine Mischung aus LINQ- und parametrisierten SQL-Abfragen.Wir haben hinzugefügt with (nolock) auf alle SQL-Abfragen.Das hat vielleicht einigen geholfen.Wir hatten auch eine einzige (sehr) schlecht geschriebene Badge-Abfrage, die ich gestern behoben habe und deren Ausführung jedes Mal mehr als 20 Sekunden dauerte und darüber hinaus jede Minute lief.Ich hatte gehofft, dass dies die Ursache für einige der Verriegelungsprobleme war!

Leider ist mir vor ca. 2 Stunden erneut ein Deadlock-Fehler aufgefallen.Dieselben genauen Symptome, genau derselbe Täter.

Das wirklich Seltsame ist, dass die oben gezeigte SQL-Anweisung zum Sperren von Schreibvorgängen Teil eines ganz bestimmten Codepfads ist.Es ist nur Wird ausgeführt, wenn einer Frage eine neue Antwort hinzugefügt wird – die übergeordnete Frage wird mit der neuen Antwortanzahl und dem letzten Datum/Benutzer aktualisiert.Das kommt im Vergleich zu der enormen Anzahl an Lesevorgängen, die wir durchführen, offensichtlich nicht so häufig vor!Soweit ich das beurteilen kann, führen wir nirgendwo in der App eine große Anzahl von Schreibvorgängen durch.

Mir ist klar, dass NOLOCK eine Art riesiger Hammer ist, aber die meisten Abfragen, die wir hier ausführen, müssen nicht so genau sein.Interessiert es Sie, wenn Ihr Benutzerprofil ein paar Sekunden veraltet ist?

Die Verwendung von NOLOCK mit Linq ist etwas schwieriger Scott Hanselman diskutiert hier.

Wir kokettieren mit der Idee, es zu nutzen

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

auf dem Basisdatenbankkontext, sodass alle unsere LINQ-Abfragen diesen Satz haben.Ohne das müssten wir jeden von uns getätigten LINQ-Aufruf (also die einfachen Leseaufrufe, die die überwiegende Mehrheit davon ausmachen) in einen 3-4-zeiligen Transaktionscodeblock einschließen, was hässlich ist.

Ich schätze, ich bin ein wenig frustriert darüber, dass triviale Lesevorgänge in SQL 2005 beim Schreiben zum Stillstand kommen können.Ich könnte mir vorstellen, dass Schreib-/Schreib-Deadlocks ein großes Problem darstellen, aber liest? Wir betreiben hier keine Bankseite, wir benötigen nicht jedes Mal perfekte Genauigkeit.

Ideen?Gedanken?


Instanziieren Sie für jeden Vorgang ein neues LINQ to SQL DataContext-Objekt oder teilen Sie möglicherweise denselben statischen Kontext für alle Ihre Aufrufe?

Jeremy, wir teilen größtenteils einen statischen Datenkontext im Basis-Controller:

private DBContext _db;
/// <summary>
/// Gets the DataContext to be used by a Request's controllers.
/// </summary>
public DBContext DB
{
    get
    {
        if (_db == null)
        {
            _db = new DBContext() { SessionName = GetType().Name };
            //_db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
        }
        return _db;
    }
}

Empfehlen Sie, dass wir für jeden Controller oder pro Seite einen neuen Kontext erstellen?öfters?

War es hilfreich?

Lösung

Laut MSDN:

http://msdn.microsoft.com/en-us/library/ms191242.aspx

Wenn entweder der LEAD -festgelegte Snapshot oder die Erlaubnis der Snapshot -Isolationsdatenbankoptionen ermöglichen, werden logische Kopien (Versionen) für alle in der Datenbank durchgeführten Datenänderungen verwaltet.Jedes Mal, wenn eine Zeile durch eine bestimmte Transaktion geändert wird, speichert die Instanz der Datenbank -Engine eine Version des zuvor engagierten Bildes der Zeile in TEMPDB.Jede Version ist mit der Transaktionssequenznummer der Transaktion gekennzeichnet, die die Änderung vorgenommen hat.Die Versionen von modifizierten Zeilen werden mit einer Linkliste gekettet.Der neueste Zeilenwert wird immer in der aktuellen Datenbank gespeichert und an die in TEMPDB gespeicherten versionierten Zeilen gekettet.

Für kurzfristige Transaktionen kann eine Version einer modifizierten Zeile im Pufferpool zwischengespeichert werden, ohne in die Festplattendateien der TEMPDB-Datenbank geschrieben zu werden.Wenn die benötigte Zeile nur von kurzer Dauer ist, wird sie einfach aus dem Pufferpool fallen gelassen und kann nicht unbedingt E/A-Overhead entstehen.

Der zusätzliche Overhead scheint eine leichte Leistungseinbuße zu verursachen, die jedoch möglicherweise vernachlässigbar ist.Wir sollten testen, um sicherzugehen.

Versuchen Sie, diese Option festzulegen und alle NOLOCKs aus Codeabfragen zu entfernen, es sei denn, dies ist wirklich notwendig.NOLOCKs oder die Verwendung globaler Methoden im Datenbank-Kontexthandler zur Bekämpfung der Isolationsstufen von Datenbanktransaktionen sind Nothilfen für das Problem.NOLOCKS verschleiert grundlegende Probleme mit unserer Datenschicht und führt möglicherweise zur Auswahl unzuverlässiger Daten, wobei die automatische Zeilenversionierung zum Auswählen/Aktualisieren die Lösung zu sein scheint.

ALTER Database [StackOverflow.Beta] SET READ_COMMITTED_SNAPSHOT ON

Andere Tipps

KEIN SCHLOSS Und LESEN SIE UNVERPFLICHTET sind ein rutschiger Abhang.Sie sollten sie niemals verwenden, es sei denn, Sie verstehen zuerst, warum der Deadlock auftritt.Es würde mich beunruhigen, wenn Sie sagen: „Wir haben mit (nolock) zu allen SQL-Abfragen hinzugefügt.“Muss hinzugefügt werden MIT NOLOCK Überall ist ein sicheres Zeichen dafür, dass Sie Probleme in Ihrer Datenschicht haben.

Die Update-Anweisung selbst sieht etwas problematisch aus.Ermitteln Sie die Anzahl früher in der Transaktion oder ziehen Sie sie einfach von einem Objekt ab? AnswerCount = AnswerCount+1 Wenn eine Frage hinzugefügt wird, ist dies wahrscheinlich eine bessere Möglichkeit, damit umzugehen.Dann benötigen Sie keine Transaktion, um die korrekte Anzahl zu erhalten, und Sie müssen sich keine Sorgen über das Parallelitätsproblem machen, dem Sie möglicherweise ausgesetzt sind.

Eine einfache Möglichkeit, diese Art von Deadlock-Problem ohne großen Aufwand und ohne Aktivierung von Dirty Reads zu umgehen, ist die Verwendung von "Snapshot Isolation Mode" (neu in SQL 2005), wodurch Sie immer die letzten unveränderten Daten sauber lesen können.Sie können blockierte Anweisungen auch relativ einfach abfangen und erneut versuchen, wenn Sie sie ordnungsgemäß behandeln möchten.

Die OP-Frage bestand darin, zu fragen, warum dieses Problem aufgetreten ist.Dieser Beitrag soll eine Antwort darauf geben, während mögliche Lösungen von anderen erarbeitet werden müssen.

Dies ist wahrscheinlich ein indexbezogenes Problem.Nehmen wir zum Beispiel an, dass die Tabelle „Posts“ einen nicht gruppierten Index X hat, der die ParentID und eines (oder mehrere) der zu aktualisierenden Felder (AnswerCount, LastActivityDate, LastActivityUserId) enthält.

Ein Deadlock würde auftreten, wenn der Befehl SELECT eine gemeinsame Lesesperre für Index Sperre für den Clustered-Index und muss eine exklusive Schreibsperre für Index X erhalten, um ihn zu aktualisieren.

Sie haben jetzt eine Situation, in der A X gesperrt hat und versucht, Y zu bekommen, während B Y gesperrt hat und versucht, X zu bekommen.

Natürlich muss der OP seinen Beitrag mit weiteren Informationen darüber aktualisieren, welche Indizes im Spiel sind, um zu bestätigen, ob dies tatsächlich die Ursache ist.

Diese Frage und die dazugehörigen Antworten sind mir ziemlich unangenehm.Es gibt viele „Probieren Sie diesen Zauberstaub!“Nein, dieser magische Staub!“

Ich kann nirgendwo sehen, dass Sie die Sperren, die genommen werden, analysiert und festgestellt haben, welche Art von Sperren genau blockiert sind.

Sie haben lediglich angegeben, dass einige Sperren auftreten – nicht, was Deadlocks sind.

In SQL 2005 können Sie weitere Informationen darüber erhalten, welche Sperren aufgehoben werden, indem Sie Folgendes verwenden:

DBCC TRACEON (1222, -1)

So erhalten Sie im Falle eines Deadlocks eine bessere Diagnose.

Instanziieren Sie für jeden Vorgang ein neues LINQ to SQL DataContext-Objekt oder teilen Sie möglicherweise denselben statischen Kontext für alle Ihre Aufrufe?Ich habe ursprünglich den letzteren Ansatz ausprobiert, und soweit ich mich erinnere, verursachte er unerwünschte Sperren in der Datenbank.Ich erstelle jetzt für jede atomare Operation einen neuen Kontext.

Bevor Sie das Haus niederbrennen, um mit NOLOCK überall eine Fliege zu fangen, sollten Sie sich vielleicht das Deadlock-Diagramm ansehen, das Sie mit Profiler hätten erfassen sollen.

Denken Sie daran, dass ein Deadlock (mindestens) 2 Sperren erfordert.Anschluss 1 hat Lock A, will Lock B – und umgekehrt für Anschluss 2.Das ist eine unlösbare Situation, und jemand muss nachgeben.

Was Sie bisher gezeigt haben, wird durch einfaches Sperren gelöst, was SQL Server gerne den ganzen Tag über tut.

Ich vermute, dass Sie (oder LINQ) eine Transaktion mit dieser UPDATE-Anweisung starten und vorher eine andere Information auswählen.Sie müssen jedoch unbedingt das Deadlock-Diagramm zurückverfolgen, um die Sperren zu finden gehaltenen von jedem Thread ausgeführt und dann durch den Profiler zurückverfolgt, um die Anweisungen zu finden, die zur Erteilung dieser Sperren geführt haben.

Ich gehe davon aus, dass es mindestens 4 Anweisungen gibt, um dieses Rätsel zu lösen (oder eine Anweisung, die mehrere Sperren erfordert – vielleicht gibt es einen Auslöser in der Posts-Tabelle?).

Interessiert es Sie, wenn Ihr Benutzerprofil ein paar Sekunden veraltet ist?

Nein – das ist vollkommen akzeptabel.Das Festlegen der Basistransaktionsisolationsstufe ist wahrscheinlich der beste/sauberste Weg.

Ein typischer Lese-/Schreib-Deadlock entsteht durch den Zugriff auf die Indexreihenfolge.Read (T1) lokalisiert die Zeile auf Index A und sucht dann nach der projizierten Spalte auf Index B (normalerweise geclustert).Schreiben (T2) ändert Index B (den Cluster) und muss dann den Index A aktualisieren.T1 hat S-Lck auf A, will S-Lck auf B, T2 hat X-Lck auf B, will U-Lck auf A.Stillstand, Puff.T1 wird getötet.Dies ist in Umgebungen mit starkem OLTP-Verkehr und etwas zu vielen Indizes weit verbreitet :).Die Lösung besteht darin, dafür zu sorgen, dass der Lesevorgang entweder nicht von A nach B springen muss (d. h.Spalte in A einschließen oder Spalte aus der projizierten Liste entfernen) oder T2 muss nicht von B nach A springen (indizierte Spalte nicht aktualisieren).Leider ist Linq hier nicht dein Freund ...

@Jeff – Ich bin definitiv kein Experte auf diesem Gebiet, aber ich habe bei fast jedem Anruf gute Ergebnisse mit der Instanziierung eines neuen Kontexts erzielt.Ich denke, es ähnelt dem Erstellen eines neuen Verbindungsobjekts bei jedem Aufruf mit ADO.Der Overhead ist nicht so groß, wie Sie denken, da Verbindungspooling ohnehin weiterhin verwendet wird.

Ich verwende einfach einen globalen statischen Helfer wie diesen:

public static class AppData
{
    /// <summary>
    /// Gets a new database context
    /// </summary>
    public static CoreDataContext DB
    {
        get
        {
            var dataContext = new CoreDataContext
            {
                DeferredLoadingEnabled = true
            };
            return dataContext;
        }
    }
}

und dann mache ich so etwas:

var db = AppData.DB;

var results = from p in db.Posts where p.ID = id select p;

Und das Gleiche würde ich auch für Updates tun.Wie auch immer, ich habe nicht annähernd so viel Datenverkehr wie Sie, aber es kam definitiv zu Sperrungen, als ich zu Beginn einen gemeinsam genutzten DataContext mit nur einer Handvoll Benutzern verwendete.Keine Garantie, aber es könnte einen Versuch wert sein.

Aktualisieren:Wenn Sie sich jedoch Ihren Code ansehen, teilen Sie den Datenkontext nur für die Lebensdauer dieser bestimmten Controller-Instanz, was grundsätzlich in Ordnung zu sein scheint, es sei denn, er wird irgendwie gleichzeitig von mehreren Aufrufen innerhalb des Controllers verwendet.In einem Thread zu diesem Thema sagte ScottGu:

Controller leben nur für eine einzelne Anfrage – daher werden sie am Ende der Verarbeitung einer Anfrage durch die Garbage Collection erfasst (was bedeutet, dass der DataContext erfasst wird) ...

Also egal, das ist es vielleicht nicht, aber auch hier ist es wahrscheinlich einen Versuch wert, vielleicht in Verbindung mit einigen Lasttests.

Q.Warum speichern Sie das AnswerCount im Posts Tisch überhaupt?

Ein alternativer Ansatz besteht darin, das „Zurückschreiben“ zu eliminieren Posts Tabelle, indem Sie die nicht speichern AnswerCount in der Tabelle, sondern um die Anzahl der Antworten auf den Beitrag je nach Bedarf dynamisch zu berechnen.

Ja, das bedeutet, dass Sie eine zusätzliche Abfrage ausführen:

SELECT COUNT(*) FROM Answers WHERE post_id = @id

oder typischer (wenn Sie dies für die Startseite anzeigen):

SELECT p.post_id, 
     p.<additional post fields>,
     a.AnswerCount
FROM Posts p
    INNER JOIN AnswersCount_view a
    ON <join criteria>
WHERE <home page criteria>

Dies führt jedoch normalerweise zu einem INDEX SCAN und kann bei der Nutzung von Ressourcen effizienter sein als bei der Nutzung READ ISOLATION.

Es gibt mehr als eine Möglichkeit, eine Katze zu häuten.Eine vorzeitige Denormalisierung eines Datenbankschemas kann zu Skalierbarkeitsproblemen führen.

Sie möchten unbedingt, dass READ_COMMITTED_SNAPSHOT aktiviert ist, was standardmäßig nicht der Fall ist.Das gibt Ihnen MVCC-Semantik.Es ist dasselbe, was Oracle standardmäßig verwendet.Eine MVCC-Datenbank zu haben ist unglaublich nützlich, es wäre verrückt, keine zu verwenden.Dadurch können Sie Folgendes innerhalb einer Transaktion ausführen:

BENUTZER aktualisieren Set FirstName = 'foobar';//Entscheide, ein Jahr lang zu schlafen.

In der Zwischenzeit kann jeder weiterhin problemlos aus dieser Tabelle auswählen, ohne sich auf das oben Genannte festzulegen.Wenn Sie mit MVCC nicht vertraut sind, werden Sie schockiert sein, dass Sie jemals ohne es leben konnten.Ernsthaft.

Es ist keine gute Idee, die Standardeinstellung auf „read uncommitted“ zu setzen.Sie werden zweifellos Inkonsistenzen einführen und am Ende ein Problem haben, das schlimmer ist als das, was Sie jetzt haben.Die Snapshot-Isolierung funktioniert möglicherweise gut, stellt jedoch eine drastische Änderung der Funktionsweise von SQL Server dar und stellt eine … riesig Auf tempdb laden.

Folgendes sollten Sie tun:Verwenden Sie try-catch (in T-SQL), um den Deadlock-Zustand zu erkennen.Wenn es passiert, führen Sie die Abfrage einfach erneut aus.Dies ist die Standardpraxis der Datenbankprogrammierung.

Gute Beispiele für diese Technik gibt es bei Paul Nielson SQL Server 2005-Bibel.

Hier ist eine kurze Vorlage, die ich verwende:

-- Deadlock retry template

declare @lastError int;
declare @numErrors int;

set @numErrors = 0;

LockTimeoutRetry:

begin try;

-- The query goes here

return; -- this is the normal end of the procedure

end try begin catch
    set @lastError=@@error
    if @lastError = 1222 or @lastError = 1205 -- Lock timeout or deadlock
    begin;
        if @numErrors >= 3 -- We hit the retry limit
        begin;
            raiserror('Could not get a lock after 3 attempts', 16, 1);
            return -100;
        end;

        -- Wait and then try the transaction again
        waitfor delay '00:00:00.25';
        set @numErrors = @numErrors + 1;
        goto LockTimeoutRetry;

    end;

    -- Some other error occurred
    declare @errorMessage nvarchar(4000), @errorSeverity int
    select    @errorMessage = error_message(),
            @errorSeverity = error_severity()

    raiserror(@errorMessage, @errorSeverity, 1)

    return -100
end catch;    

Eine Sache, die in der Vergangenheit für mich funktioniert hat, ist sicherzustellen, dass alle meine Abfragen und Aktualisierungen in der gleichen Reihenfolge auf Ressourcen (Tabellen) zugreifen.

Das heißt, wenn eine Abfrage in der Reihenfolge Tabelle1, Tabelle2 aktualisiert wird und eine andere Abfrage sie in der Reihenfolge Tabelle2, Tabelle1 aktualisiert, kann es zu Deadlocks kommen.

Ich bin mir nicht sicher, ob Sie die Reihenfolge der Aktualisierungen ändern können, da Sie LINQ verwenden.Aber es ist etwas, das man sich ansehen kann.

Interessiert es Sie, wenn Ihr Benutzerprofil ein paar Sekunden veraltet ist?

Ein paar Sekunden wären auf jeden Fall akzeptabel.Es sieht sowieso nicht so aus, als würde es so lange dauern, es sei denn, dass eine große Anzahl von Leuten gleichzeitig Antworten einsendet.

In diesem Punkt stimme ich Jeremy zu.Sie fragen, ob Sie für jeden Controller oder pro Seite einen neuen Datenkontext erstellen sollen – ich neige dazu, für jede unabhängige Abfrage einen neuen zu erstellen.

Ich baue derzeit eine Lösung auf, die früher wie Sie den statischen Kontext implementierte, und als ich während Stresstests Tonnen von Anfragen an das Biest eines Servers (Millionen+) warf, erhielt ich auch zufällig Lese-/Schreibsperren.

Sobald ich meine Strategie änderte, um pro Abfrage einen anderen Datenkontext auf LINQ-Ebene zu verwenden, und darauf vertraute, dass SQL Server seine Verbindungspooling-Magie entfalten konnte, schienen die Sperren zu verschwinden.

Natürlich stand ich unter Zeitdruck und habe mehrere Dinge gleichzeitig ausprobiert. Daher kann ich nicht hundertprozentig sicher sein, dass das die Lösung war, aber ich habe ein hohes Maß an Selbstvertrauen – sagen wir es mal so .

Sie sollten Dirty Reads implementieren.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

Wenn Sie bei Ihren Abfragen nicht unbedingt eine perfekte Transaktionsintegrität benötigen, sollten Sie beim Zugriff auf Tabellen mit hoher Parallelität Dirty Reads verwenden.Ich gehe davon aus, dass Ihre Posts-Tabelle eine davon ist.

Dies kann zu sogenannten „Phantom-Lesevorgängen“ führen, bei denen Ihre Abfrage Daten aus einer Transaktion verarbeitet, die noch nicht festgeschrieben wurde.

Wir betreiben hier keine Bankseite, wir benötigen nicht jedes Mal perfekte Genauigkeit

Verwenden Sie Dirty Reads.Sie haben Recht damit, dass sie Ihnen keine perfekte Genauigkeit bieten, aber sie sollten Ihre Dead-Locking-Probleme klären.

Ohne das müssten wir jeden von uns getätigten LINQ-Aufruf (also die einfachen Leseaufrufe, die die überwiegende Mehrheit davon ausmachen) in einen 3-4-zeiligen Transaktionscodeblock einschließen, was hässlich ist

Wenn Sie Dirty Reads im „Basisdatenbankkontext“ implementieren, können Sie Ihre einzelnen Aufrufe jederzeit mit einer höheren Isolationsstufe umschließen, wenn Sie die Transaktionsintegrität benötigen.

Was ist also das Problem bei der Implementierung eines Wiederholungsmechanismus?Es besteht immer die Möglichkeit, dass ein Deadlock auftritt. Warum also nicht eine Logik haben, um ihn zu identifizieren, und es einfach noch einmal versuchen?

Werden nicht zumindest einige der anderen Optionen zu Leistungseinbußen führen, die ständig in Kauf genommen werden, wenn ein Wiederholungssystem nur selten zum Einsatz kommt?

Vergessen Sie auch nicht, bei jedem erneuten Versuch eine Art Protokollierung durchzuführen, damit Sie nicht in die Situation geraten, dass es selten zu häufig kommt.

Jetzt, wo ich Jeremys Antwort sehe, erinnere ich mich, dass ich gehört habe, dass die beste Vorgehensweise darin besteht, für jede Datenoperation einen neuen DataContext zu verwenden.Rob Conery hat mehrere Beiträge über DataContext geschrieben, und er bringt sie immer auf den neuesten Stand, anstatt einen Singleton zu verwenden.

Hier ist das Muster, das wir für Video.Show verwendet haben (Link zur Quellansicht in CodePlex):

using System.Configuration;
namespace VideoShow.Data
{
  public class DataContextFactory
  {
    public static VideoShowDataContext DataContext()
    {
        return new VideoShowDataContext(ConfigurationManager.ConnectionStrings["VideoShowConnectionString"].ConnectionString);
    }
    public static VideoShowDataContext DataContext(string connectionString)
    {
        return new VideoShowDataContext(connectionString);
    }
  }
}

Dann auf Serviceebene (oder noch detaillierter, für Updates):

private VideoShowDataContext dataContext = DataContextFactory.DataContext();

public VideoSearchResult GetVideos(int pageSize, int pageNumber, string sortType)
{
  var videos =
  from video in DataContext.Videos
  where video.StatusId == (int)VideoServices.VideoStatus.Complete
  orderby video.DatePublished descending
  select video;
  return GetSearchResult(videos, pageSize, pageNumber);
}

Ich muss Greg zustimmen, solange das Festlegen der Isolationsstufe auf „Lesen nicht festgeschrieben“ keine negativen Auswirkungen auf andere Abfragen hat.

Es würde mich interessieren, Jeff, wie sich die Einstellung auf Datenbankebene auf eine Abfrage wie die folgende auswirken würde:

Begin Tran
Insert into Table (Columns) Values (Values)
Select Max(ID) From Table
Commit Tran

Für mich ist es kein Problem, wenn mein Profil auch nur mehrere Minuten veraltet ist.

Versuchen Sie den Lesevorgang erneut, nachdem er fehlgeschlagen ist?Wenn man eine Menge zufälliger Lesevorgänge auslöst, ist es sicherlich möglich, dass einige zuschlagen, wenn sie nicht lesen können.Bei den meisten Anwendungen, mit denen ich arbeite, gibt es im Vergleich zur Anzahl der Lesevorgänge nur sehr wenige Schreibvorgänge, und ich bin mir sicher, dass die Anzahl der Lesevorgänge nicht annähernd so hoch ist wie die, die Sie erhalten.

Wenn die Implementierung von „READ UNCOMMITTED“ Ihr Problem nicht löst, ist es schwierig zu helfen, ohne viel mehr über die Verarbeitung zu wissen.Möglicherweise gibt es eine andere Optimierungsoption, die dieses Verhalten verbessern würde.Sofern kein MSSQL-Guru zu Hilfe kommt, empfehle ich, das Problem dem Anbieter zu melden.

Ich würde weiterhin alles tunen;Wie funktioniert die Leistung des Festplattensubsystems?Wie groß ist die durchschnittliche Länge der Festplattenwarteschlange?Wenn die E/A-Vorgänge gesichert sind, liegt das eigentliche Problem möglicherweise nicht in diesen beiden Abfragen, die einen Deadlock verursachen, sondern möglicherweise in einer anderen Abfrage, die einen Engpass im System verursacht.Sie haben eine optimierte Abfrage erwähnt, die 20 Sekunden dauert. Gibt es noch andere?

Konzentrieren Sie sich darauf, die lang laufenden Abfragen zu verkürzen. Ich wette, die Deadlock-Probleme werden verschwinden.

Hatte das gleiche Problem und kann „IsolationLevel = IsolationLevel.ReadUncommitted“ auf TransactionScope nicht verwenden, da auf dem Server DTS nicht aktiviert ist (!).

Das habe ich mit einer Erweiterungsmethode gemacht:

public static void SetNoLock(this MyDataContext myDS)
{
    myDS.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}

Für Selects, die kritische Parallelitätstabellen verwenden, aktivieren wir also den „Nolock“ wie folgt:

using (MyDataContext myDS = new MyDataContext())
{
   myDS.SetNoLock();

   //  var query = from ...my dirty querys here...
}

Vorschläge sind willkommen!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top