SQL Server Deadlock trên hai bản cập nhật do thứ tự khóa chỉ mục


11

Tôi có hai CẬP NHẬT - một khóa CI trước và sau đó là NCI (về trạng thái) vì cột trạng thái cũng đang được cập nhật. Người kia đã sở hữu khóa U trên NCI vì họ biết nó đang thay đổi và sau đó cố gắng lấy khóa U trên CI.

Cách dễ nhất để buộc những thứ này nối tiếp là gì? Có vẻ kỳ quặc khi sử dụng gợi ý cấp BẢNG vì đây là vấn đề lập chỉ mục nội bộ - chỉ có một bảng liên quan - liệu UPDLOCK, HOLDLOCK có tự động chỉ áp dụng cho tất cả các chỉ mục cần thiết trên bảng đó và do đó buộc nó phải được tuần tự hóa không?

Dưới đây là các truy vấn:

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

Rằng một khóa X khóa hàng trong CI (trên cột CREATED) và sau đó cố gắng khóa X trên NCI bao gồm cột trạng thái.

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)

Cái này U khóa cùng NCI - đối với truy vấn lồng nhau tôi đoán, sau đó đi đến khóa CI để cập nhật.

Do đó, trật tự tạo ra bế tắc.

Giải pháp dễ nhất là buộc hai truy vấn chặn hoàn toàn - tức là tuần tự hóa. Cách dễ nhất để ép buộc điều đó, chỉ cần đặt WITH (UPDLOCK, HOLDLOCK)các tham chiếu đến bảng (một trong hai và một trong hai)?

DDL:

Lưu ý khách hàng có nhiều chỉ mục trên bảng này sẽ bị ảnh hưởng bởi bản cập nhật này, nhưng không được đề cập trong biểu đồ khóa chết.

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]

Câu trả lời:


13

Chỉ mục tối ưu cho hai truy vấn đó không xa định nghĩa hiện tại của IK_HTT_ACTION_LOG_1chỉ mục (thêm ACTION_UUIDdưới dạng INCLUDEchỉ mục được cải thiện bên dưới):

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

Truy vấn đầu tiên là:

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

Đưa ra kế hoạch thực hiện sau:

Cập nhật 1

Truy vấn thứ hai có thể được thể hiện theo cách này:

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;

Đưa ra kế hoạch thực hiện này:

Cập nhật 2

Cả hai truy vấn hiện truy cập cùng một tài nguyên theo cùng một thứ tự, trong khi khóa nhiều hàng ít hơn ở phía đọc của kế hoạch. Công cụ thực thi sẽ tự động mất UPDLOCKkhi đọc chỉ mục mới, cung cấp tuần tự hóa mà bạn đang tìm kiếm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.