इंडेक्स लॉक ऑर्डर के कारण दो अपडेट पर SQL सर्वर डेडलॉक


11

मेरे पास दो UPDATE हैं - एक पहले CI को लॉक करता है और फिर NCI (स्टेटस पर) क्योंकि स्टेटस कॉलम को भी अपडेट किया जा रहा है। दूसरा पहले से ही NCI पर U लॉक का मालिक है क्योंकि वह जानता है कि यह बदल रहा है और फिर CI पर U लॉक प्राप्त करने की कोशिश करता है।

इन्हें क्रमबद्ध करने के लिए सबसे आसान तरीका क्या है? एक TABLE-level hint का उपयोग करना अजीब लगता है क्योंकि यह एक आंतरिक अनुक्रमण मुद्दा है - इसमें केवल एक तालिका शामिल है - क्या UPDLOCK, HOLDLOCK स्वचालित रूप से बस उस तालिका पर आवश्यक सभी अनुक्रमणिकाओं पर लागू होता है और इस तरह इसे क्रमबद्ध करने के लिए मजबूर करता है?

यहाँ प्रश्न हैं:

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

वह एक X CI (क्रिएट किए गए कॉलम) में पंक्ति को लॉक करता है और फिर NCI पर X लॉक करने का प्रयास करता है जिसमें स्टेटस कॉलम शामिल होता है।

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:

नोट क्लाइंट के पास इस तालिका पर अधिक अनुक्रमणिकाएँ हैं जो इस अद्यतन से प्रभावित होनी चाहिए, लेकिन गतिरोध ग्राफ़ में इसका उल्लेख नहीं किया गया है।

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';

निम्नलिखित निष्पादन योजना देते हुए:

अपडेट १

दूसरी क्वेरी इस तरह व्यक्त की जा सकती है:

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;

इस निष्पादन योजना को देना:

अपडेट २

दोनों प्रश्न अब एक ही क्रम में समान संसाधनों तक पहुंचते हैं, जबकि योजना के रीड साइड पर कई कम पंक्तियों को लॉक करते हैं। निष्पादन UPDLOCKसूचकांक स्वचालित रूप से नए सूचकांक को पढ़ते समय ले जाएगा , आप जो क्रमबद्धता देख रहे हैं, उसे प्रदान करना।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.