Gibt es eine hilfreichere Möglichkeit, Statistiken zum Erfassen / Freigeben von Sperren in SQL Profiler zu erkennen?

8

Ich habe ein paar Deadlocks auf unserem Live-Server, ich weiß, es ist scheiße.

Wie auch immer, ich versuche herauszufinden, wie ich feststellen kann, welcher SQL-Code die Sperren verursacht (oder ihn zu lange hält).

Ich habe alle Locks- Ereignisse hinzugefügt (erworben, Deadlock, Eskalation, freigegeben, Timeout usw.), aber alles, was ich sehe, ist eine Bombardierung erworbener / freigegebener Ereignisse, mit nicht viel zusätzlichen Informationen.

Ich bin mir ziemlich sicher, dass ich das "Szenario" kenne, das die Deadlocks verursacht, da wir nach einem INSERT / UPDATE / DELETE einen Trigger auf einer Tabelle haben, und dies macht eine Menge zusätzlicher Arbeit, manchmal bis zu 8 Sekunden wert.

Während des Großteils dieser zusätzlichen Arbeit werden Daten aus Tabelle A abgerufen und in eine Tabellenvariable eingefügt. Auf dieser Tabellenvariablen werden viele Arbeitsspeicher gespeichert (ca. 6 Sekunden vergehen), und schließlich erfolgt eine Einfügung in Tabelle B.

Frage: Würde das tatsächlich eine Tabellensperre für die gesamte Tabelle verursachen, obwohl ich nur bestimmte Zeilen in einer Tabellenvariablen auswähle ?

Ich habe "Trigger Tracing" hinzugefügt (in Tabelle x Werte einfügen ('hi im here') usw.) und ich weiß im Grunde, dass die Prozedur am längsten dauert (und daher wahrscheinlich die Sperre verursachen muss?)

Aber ich bin mir immer noch nicht sicher, warum der Deadlock passiert.

Frage: Ich kann sehen, dass 2 Sperreneskalationen auftreten. Bedeutet dies, dass Zeilensperren zu Tabellensperren eskaliert wurden?

Frage: Kann mir jemand Tipps geben, wie ich diesen Stillstand weiter verfolgen kann?

BEARBEITEN:

Hier ist das Deadlock-Diagramm

EDIT 2:

Hier ist der Code für [UpdatePostsCleanedUriUniqueUri], der möglicherweise eine Tabellensperre verursacht?

ALTER PROC [dbo].[UpdatePostsCleanedUriUniqueUri]
(
    @PostIds IdentityType READONLY
)
AS
    SET NOCOUNT ON


    -- *************************************************************************
    -- ******************* Create the Cleaned Uri's,  first ********************
    -- *************************************************************************

    ---- "Remove" any existing cleaned uri's, per location
    UPDATE a
    SET a.CleanedUri = NEWID(),
        a.UniqueUri = NEWID()
    FROM [dbo].[Posts] a
        INNER JOIN @PostIds b ON a.PostId = b.Id


    -- ** Now add the cleaned uri.
    UPDATE a
    SET a.CleanedUri = [dbo].[ToFixedLengthToString](
        [dbo].[IsNullOrEmpty](LOWER([dbo].[ToAlphaNumericText]([Subject], '-', 1)), 'unknown'), 60, '')
    FROM [dbo].[Posts] a
        INNER JOIN @PostIds b ON a.PostId = b.Id



    -- *************************************************************************
    -- ******** Now create the Unique Uri from the cleaned one, above **********
    -- *************************************************************************

    -- Now Re-Add these unique uri's.
    ;WITH CTE AS (
        SELECT DISTINCT CleanedUri
        FROM [dbo].[Posts] a
            INNER JOIN @PostIds b ON a.PostId = b.Id
    )

    UPDATE a
    SET a.UniqueUri = Result.UniqueUri
    FROM [dbo].[Posts] a
        INNER JOIN (
            SELECT SubQuery.PostId, 
                CASE SubQuery.RowNumber
                WHEN 1 THEN SubQuery.CleanedUri
                ELSE SubQuery.CleanedUri + '-' + CAST(SubQuery.RowNumber - 1 AS NVARCHAR(20)) END AS UniqueUri 
            FROM (
                SELECT PostId, a.CleanedUri,
                    ROW_NUMBER() OVER (PARTITION BY a.CleanedUri ORDER BY a.CleanedUri) AS RowNumber
                FROM [dbo].[Posts] a
                    INNER JOIN CTE b ON a.CleanedUri = b.CleanedUri
            ) SubQuery
        ) Result ON a.PostId = Result.PostId
    ;

Da es einen INNER JOIN hat, hätte ich gedacht, dass es nur die übereinstimmenden Zeilen sperren würde? Oder sollte ich verwenden WITH (ROWLOCK)?

EDIT 3:

    USE [XWing]
    GO

    /****** Object:  Table [dbo].[Posts]    Script Date: 02/17/2012 13:29:05 ******/
    SET ANSI_NULLS ON
    GO

    SET QUOTED_IDENTIFIER ON
    GO

    SET ANSI_PADDING ON
    GO

    CREATE TABLE [dbo].[Posts](
        [PostId] [int] IDENTITY(1,1) NOT NULL,
        [Subject] [nvarchar](300) NULL,
        [CleanedUri] [nvarchar](70) NOT NULL,
        [UniqueUri] [nvarchar](70) NOT NULL,
        [Content] [nvarchar](max) NULL,
        [Source] [nvarchar](50) NULL,
        [LocationTypeId] [tinyint] NOT NULL,
        [CreatedOn] [smalldatetime] NOT NULL,
        [ModifiedOn] [smalldatetime] NOT NULL,
        [IsEditorsChoice] [bit] NOT NULL,
        [IsVisible] [bit] NOT NULL,
        [UserId] [int] NOT NULL,
        [LatLongPoint] [geography] NULL,
        [UserLastIpAddress] [varchar](15) NULL,
        [OldPostId] [int] NULL,
        [OldUniqueUri] [nvarchar](250) NULL,
        [ThemeId] [int] NOT NULL,
     CONSTRAINT [PK_Posts] PRIMARY KEY CLUSTERED 
    (
        [PostId] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

    SET ANSI_PADDING OFF
    GO

    ALTER TABLE [dbo].[Posts]  WITH CHECK ADD  CONSTRAINT [FK_Posts_Themes] FOREIGN KEY([ThemeId])
    REFERENCES [dbo].[Themes] ([ThemeId])
    GO

    ALTER TABLE [dbo].[Posts] CHECK CONSTRAINT [FK_Posts_Themes]
    GO

    ALTER TABLE [dbo].[Posts]  WITH CHECK ADD  CONSTRAINT [FK_Posts_Users] FOREIGN KEY([UserId])
    REFERENCES [dbo].[Users] ([UserId])
    GO

    ALTER TABLE [dbo].[Posts] CHECK CONSTRAINT [FK_Posts_Users]
    GO

    ALTER TABLE [dbo].[Posts] ADD  CONSTRAINT [DF_Posts_IsEditorsChoice]  DEFAULT ((0)) FOR [IsEditorsChoice]
    GO

    ALTER TABLE [dbo].[Posts] ADD  CONSTRAINT [DF_Posts_ThemeId]  DEFAULT ((1)) FOR [ThemeId]
    GO

USE [XWing]
GO

/****** Object:  Index [IX_Posts_IsEditorsChoice_Include_PostId_LocationTypeId]    Script Date: 02/17/2012 13:31:59 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_IsEditorsChoice_Include_PostId_LocationTypeId] ON [dbo].[Posts] 
(
    [IsEditorsChoice] ASC
)
INCLUDE ( [PostId],
[LocationTypeId]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

USE [XWing]
GO

/****** Object:  Index [IX_Posts_IsVisible]    Script Date: 02/17/2012 13:32:02 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_IsVisible] ON [dbo].[Posts] 
(
    [IsVisible] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

USE [XWing]
GO

/****** Object:  Index [IX_Posts_LocationTypeId]    Script Date: 02/17/2012 13:32:07 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_LocationTypeId] ON [dbo].[Posts] 
(
    [LocationTypeId] ASC
)
INCLUDE ( [PostId]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

USE [XWing]
GO

/****** Object:  Index [IX_Posts_OldPostId]    Script Date: 02/17/2012 13:32:12 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_OldPostId] ON [dbo].[Posts] 
(
    [OldPostId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

USE [XWing]
GO

/****** Object:  Index [IX_Posts_UserId]    Script Date: 02/17/2012 13:32:17 ******/
CREATE NONCLUSTERED INDEX [IX_Posts_UserId] ON [dbo].[Posts] 
(
    [UserId] ASC
)
INCLUDE ( [PostId]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

USE [XWing]
GO

/****** Object:  Index [SX_Posts_Location]    Script Date: 02/17/2012 13:32:22 ******/
CREATE SPATIAL INDEX [SX_Posts_Location] ON [dbo].[Posts] 
(
    [LatLongPoint]
)USING  GEOGRAPHY_GRID 
WITH (
GRIDS =(LEVEL_1 = LOW,LEVEL_2 = LOW,LEVEL_3 = MEDIUM,LEVEL_4 = HIGH), 
CELLS_PER_OBJECT = 16, PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

USE [XWing]
GO

/****** Object:  Index [UIX_Posts_UniqueUri]    Script Date: 02/17/2012 13:32:41 ******/
CREATE UNIQUE NONCLUSTERED INDEX [UIX_Posts_UniqueUri] ON [dbo].[Posts] 
(
    [UniqueUri] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON, FILLFACTOR = 80) ON [PRIMARY]
GO

BEARBEITEN 4

Hier ist der Ausführungsplan für UpdatePostsCleanedUriUniqueUri, nachdem der folgende Index für CleanedUri hinzugefügt wurde:

CREATE NONCLUSTERED INDEX [IX_Posts_CleanedUri_Include_PostId] ON [dbo].[Posts] 
(
    [CleanedUri] ASC
)
INCLUDE ( [PostId]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
RPM1984
quelle

Antworten:

13

Würde das tatsächlich eine Tabellensperre für die gesamte Tabelle verursachen, obwohl ich nur bestimmte Zeilen in einer Tabellenvariablen auswähle?

Eskalation sperren. Wenn Ihr ‚ die Option‘ ist nicht ... selektiv, wenn es hat scannen große Teile einer Tabelle dann kann der Motor zu Tabellensperren eskaliert. Siehe Sperreneskalation (Datenbankmodul) .

Ich kann sehen, dass 2 Sperreneskalationen auftreten. Bedeutet das, dass Zeilensperren zu Tabellensperren eskaliert wurden?

Sind sie Eskalationsereignisse sperren, oder einfach nur Eskalation sperren versucht ? Wenn sie erfolgreich waren, hat die Transaktion die gesamte Tabelle gesperrt.

Kann mir jemand Tipps geben, wie ich diesen Stillstand weiter verfolgen kann?

Dies von den einzelnen Sperren POV aus zu erreichen, ist nicht sehr produktiv. Die typische Untersuchung konzentriert sich auf die Erfassung und Analyse des Deadlock-Diagramms. Siehe Analysieren von Deadlocks mit SQL Server Profiler . Erfassen Sie das Deadlock-Diagramm und veröffentlichen Sie es hier. Vielleicht können wir Ihnen helfen. Laden Sie das XML des Deadlock-Diagramms hoch , nicht das Bild des Deadlocks, siehe Gewusst wie: Speichern von Deadlock-Diagrammen (SQL Server Profiler) .

Deadlock-Diagramm:

Spid 58 hat Seite 7: 1: 11066 im IX-Modus und blockiert Spid 61, der es im S-Modus haben möchte. Spid 61 hat Seite 7: 1: 1932345 im S-Modus und blockiert Spid 58, der eine IU-Modus-Sperre hat, diese aber in IX konvertieren möchte. Die Dinge werden durch die Hinzufügung von Parallelität und einer langen Liste von "Ich auch" -Kellnern kompliziert, aber das grundlegende Problem kann auf das oben beschriebene reduziert werden.

Dies ist ein typisches Muster für das Fehlen von Indizes. Sie haben einen Updater, XWingNew.dbo.UpdatePostsCleanedUriUniqueUrider ein Update herausgibt, das wahrscheinlich die gesamte XWingNew.dbo.PostsTabelle durchsucht . Gleichzeitig haben Sie wahrscheinlich mehrere Leser, die die gesamte Tabelle in einer von linq generierten Abfrage scannen, die im XML abgeschnitten wurde : SELECT [UnionAll3].[C2] AS [C1], [UnionAll3].[C3] AS [C2], [UnionAll3].[C4] AS [C3], [UnionAll3].[C5] AS [C4],.... Da sowohl das Update als auch die ausgewählte Problemtabelle scannen, ist ein Deadlock so gut wie garantiert, wenn das Update versucht, die in der Scanphase erworbenen IU-Seitensperren in IX-Sperren zu konvertieren, die zum Aktualisieren der qualifizierten Zeilen erforderlich sind.

Sie haben jetzt zwei Alternativen:

  • Korrigieren Sie Ihre Anwendung. Die Abfragen sind eindeutig nicht abgestimmt und es wurden keine Überlegungen zu den Indexierungsstrategien angestellt. Sie werden nicht nur das Deadlock-Problem beheben, sondern Ihre App wird auch viel schneller.
  • Der einfache Cop-Out: Aktivieren Sie den Lese-Commit-Snapshot . Dadurch werden die Anwendungsfehler nicht behoben, sondern ausgeblendet und die Deadlocks beseitigt.
Remus Rusanu
quelle