SQL Server Deadlock สำหรับการอัพเดตสองครั้งเนื่องจากคำสั่งล็อคดัชนี


11

ฉันมีการอัปเดตสองครั้ง - หนึ่งล็อค CI ก่อนจากนั้น NCI (ตามสถานะ) เนื่องจากคอลัมน์สถานะกำลังอัปเดตด้วย อีกคนหนึ่งเป็นเจ้าของล็อค U บน NCI เพราะรู้ว่ามันกำลังเปลี่ยนแปลงและพยายามดึง U ล็อคบน CI

วิธีที่ง่ายที่สุดในการบังคับให้สิ่งเหล่านี้เป็นอันดับคืออะไร ดูเหมือนแปลกที่จะใช้คำใบ้ระดับ Table เนื่องจากนี่เป็นปัญหาการจัดทำดัชนีภายใน - มีเพียงหนึ่งตารางที่เกี่ยวข้อง - UPDLOCK จะ HOLDLOCK จะใช้กับดัชนีทั้งหมดที่จำเป็นในตารางนั้นโดยอัตโนมัติหรือไม่

นี่คือแบบสอบถาม:

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

X ตัวนั้นล็อกแถวใน CI (บนคอลัมน์ CREATED) แล้วพยายามล็อก X บน NCI ซึ่งมีคอลัมน์สถานะ

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)

U อันนี้ล็อค NCI ตัวเดียวกัน - สำหรับเคียวรีที่ซ้อนกันที่ฉันเดาจากนั้นไปล็อค CI สำหรับการอัพเดต

ดังนั้นคำสั่งที่ทำให้เกิดการหยุดชะงัก

ทางออกที่ง่ายที่สุดคือบังคับให้ข้อความค้นหาทั้งสองนั้นปิดกั้นอย่างสมบูรณ์ - กล่าวคือทำให้เป็นอันดับ วิธีที่ง่ายที่สุดในการบังคับนั้นคืออะไรเพียงแค่ใส่WITH (UPDLOCK, HOLDLOCK)การอ้างอิงไปยังตาราง (หนึ่งในแรกและสองในสอง)?

DDL:

ไคลเอ็นต์ Note มีดัชนีเพิ่มเติมในตารางนี้ซึ่งควรได้รับผลกระทบจากการอัพเดตนี้ แต่ไม่ได้กล่าวถึงในกราฟการหยุดชะงัก

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]

คำตอบ:


13

ดัชนีที่ดีที่สุดสำหรับแบบสอบถามทั้งสองนั้นอยู่ไม่ไกลจากคำจำกัดความที่มีอยู่ของIK_HTT_ACTION_LOG_1ดัชนี (เพิ่มACTION_UUIDเป็นINCLUDEดัชนีที่ปรับปรุงด้านล่าง):

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

แบบสอบถามแรกคือ:

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

ให้แผนการดำเนินการต่อไปนี้:

อัปเดต 1

แบบสอบถามที่สองสามารถแสดงด้วยวิธีนี้:

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;

ให้แผนปฏิบัติการนี้:

อัปเดต 2

ขณะนี้คิวรีทั้งสองเข้าถึงทรัพยากรเดียวกันในลำดับเดียวกันในขณะที่ล็อกแถวจำนวนน้อยลงบนฝั่งอ่านของแผน เอ็นจินการดำเนินการจะใช้เวลาโดยอัตโนมัติUPDLOCKเมื่ออ่านดัชนีใหม่โดยให้การจัดลำดับที่คุณต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.