Dizin kilidi sırası nedeniyle iki güncelleştirme üzerinde SQL Server kilitlenme


11

İki GÜNCELLEMELER var - durum sütunu da güncelleniyor çünkü biri önce CI ve sonra NCI (durum) kilitler. Diğerinin NCI üzerinde zaten bir U kilidi var çünkü değiştiğini biliyor ve sonra CI üzerinde bir U kilidi almaya çalışıyor.

Bunları serileştirmeye zorlamanın en kolay yolu nedir? Bu bir dahili indeksleme sorunu olduğu için TABLO düzeyinde bir ipucu kullanmak tuhaf görünüyor - sadece bir tablo var - UPDLOCK, HOLDLOCK otomatik olarak sadece o tabloda gerekli olan tüm indekslere uygulanacak ve böylece serileştirilmeye zorlanacak mı?

İşte sorgular:

UPDATE htt_action_log
SET status = 'ABORTED', CLOSED = GETUTCDATE()
WHERE transition_uuid = '{F53ADDDA-E46B-4726-66D8-D7B640B66597}'
AND status = 'OPEN';

Bu X, CI'deki (CREATED sütununda) satırı kilitler ve ardından durum sütununu içeren NCI üzerinde X kilidini dener.

UPDATE htt_action_log
SET status = 'RUNNING {36082BCD-EB52-4358-E3D3-4D96FD5B9F0F} 1360094342'
WHERE action_uuid = (SELECT TOP 1 action_uuid
                     FROM htt_action_log
                     WHERE transition_uuid = '{F53ADDDA-E46B-4726-66D8-D7B640B66597}'
                         AND status = 'OPEN'
                     ORDER BY action_seq)

Bu U aynı NCI kilitler - sanırım iç içe sorgu için, sonra güncelleme için CI kilitlemeye gider.

Böylece düzen çıkmaz üretir.

En kolay çözüm, iki sorguyu tamamen bloke etmeye zorlamaktır. Bunu zorlamanın en kolay yolu nedir?WITH (UPDLOCK, HOLDLOCK) tabloya referanslar (ilkinde bir ve ikincisinde iki)?

DDL:

İstemcinin bu tabloda, bu güncelleştirmeden etkilenmesi gereken, ancak kilitlenme grafiğinde belirtilmeyen daha fazla dizin vardır.

CREATE TABLE [dbo].[HTT_ACTION_LOG](
    [ACTION_UUID] [varchar](128) NOT NULL,
    [TRANSITION_UUID] [varchar](128) NOT NULL,
    [STATUS] [varchar](128) NOT NULL,
    [CREATED] [datetime] NOT NULL,
    [CLOSED] [datetime] NULL,
    [ACTION_SEQ] [int] NOT NULL,
    [ACTION_TYPE] [varchar](15) NOT NULL,
    [ACTION_NAME] [varchar](50) NOT NULL,
    [ACTION_RESULT] [varchar](8000) NULL,
    [PENDING_SINCE] [datetime] NULL,
    [ACTION_SQL] [varchar](8000) NULL,
    [ERROR_OK] [int] NULL,
    [ERROR_COND] [varchar](2048) NULL,
    [RETRY] [varchar](128) NULL,
 CONSTRAINT [PK_HTT_ACTION_LOG_1] UNIQUE NONCLUSTERED 
(
    [ACTION_UUID] ASC
)
)

CREATE CLUSTERED INDEX [IK_HTT_ACTION_LOG_2] ON [dbo].[HTT_ACTION_LOG] 
(
    [CREATED] ASC
)

CREATE NONCLUSTERED INDEX [IK_HTT_ACTION_LOG_1] ON [dbo].[HTT_ACTION_LOG] 
(
    [TRANSITION_UUID] ASC,
    [STATUS] ASC
)
INCLUDE ( [ACTION_UUID],
[ACTION_SEQ])

CREATE NONCLUSTERED INDEX [IK_HTT_ACTION_LOG_4] ON [dbo].[HTT_ACTION_LOG] 
(
    [ACTION_UUID] ASC,
    [STATUS] ASC
)

CREATE NONCLUSTERED INDEX [missing_index_11438530_11438529_HTT_ACTION_LOG] ON [dbo].[HTT_ACTION_LOG] 
(
    [TRANSITION_UUID] ASC,
    [ACTION_TYPE] ASC
)
INCLUDE ( [ACTION_NAME])

CREATE NONCLUSTERED INDEX [missing_index_7207590_7207589_HTT_ACTION_LOG] ON [dbo].[HTT_ACTION_LOG] 
(
    [STATUS] ASC
)
INCLUDE ( [CREATED],
[PENDING_SINCE],
[ACTION_NAME])

CREATE NONCLUSTERED INDEX [missing_index_8535421_8535420_HTT_ACTION_LOG] ON [dbo].[HTT_ACTION_LOG] 
(
    [TRANSITION_UUID] ASC
)
INCLUDE ( [ACTION_UUID],
[STATUS])

ALTER TABLE [dbo].[HTT_ACTION_LOG] SET (LOCK_ESCALATION = AUTO)

ALTER TABLE [dbo].[HTT_ACTION_LOG]  WITH CHECK ADD  CONSTRAINT [FK_HTT_ACTION_LOG_1] FOREIGN KEY([TRANSITION_UUID])
REFERENCES [dbo].[HTT_TRANSITION_LOG] ([TRANSITION_UUID])

ALTER TABLE [dbo].[HTT_ACTION_LOG] CHECK CONSTRAINT [FK_HTT_ACTION_LOG_1]

ALTER TABLE [dbo].[HTT_ACTION_LOG] ADD  DEFAULT ('OPEN') FOR [STATUS]

ALTER TABLE [dbo].[HTT_ACTION_LOG] ADD  DEFAULT (getutcdate()) FOR [CREATED]

ALTER TABLE [dbo].[HTT_ACTION_LOG] ADD  DEFAULT ((0)) FOR [ERROR_OK]

Yanıtlar:


13

Bu iki sorgu için en uygun dizin, IK_HTT_ACTION_LOG_1dizinin mevcut tanımından çok uzakta değildir ( aşağıdaki geliştirilmiş dizine ACTION_UUIDbir INCLUDEolarak ekleyin ):

CREATE INDEX nc1
ON dbo.HTT_ACTION_LOG
(
    TRANSITION_UUID,
    STATUS,
    ACTION_SEQ
);

İlk sorgu:

UPDATE dbo.HTT_ACTION_LOG
SET [STATUS] = 'ABORTED', 
    CLOSED = GETUTCDATE()
WHERE
    TRANSITION_UUID = '{F53ADDDA-E46B-4726-66D8-D7B640B66597}'
    AND [STATUS] = 'OPEN';

Aşağıdaki yürütme planını vermek:

Güncelleme 1

İkinci sorgu şu şekilde ifade edilebilir:

UPDATE ToUpdate 
SET [STATUS] = 'RUNNING {36082BCD-EB52-4358-E3D3-4D96FD5B9F0F} 1360094342'
FROM
(
    SELECT TOP (1)
        hal.[STATUS]
    FROM dbo.HTT_ACTION_LOG AS hal
    WHERE
        hal.transition_uuid = '{F53ADDDA-E46B-4726-66D8-D7B640B66597}'
        AND hal.[STATUS] = 'OPEN'
    ORDER BY
        hal.ACTION_SEQ ASC
) AS ToUpdate;

Bu yürütme planını vermek:

Güncelleme 2

Her iki sorgu da aynı kaynaklara aynı sırayla erişirken, planın okunan tarafında daha az sayıda satırı kilitliyor. Yürütme motoru UPDLOCK, yeni dizini okurken otomatik olarak arama yapar ve aradığınız serileştirmeyi sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.