Ich habe zwei UPDATEs - eines sperrt zuerst das CI und dann das NCI (bei Status), da auch die Statusspalte aktualisiert wird. Der andere besitzt bereits eine U-Sperre für das NCI, weil er weiß, dass es sich ändert, und versucht dann, eine U-Sperre für das CI zu erhalten.
Was ist der einfachste Weg, um diese zur Serialisierung zu zwingen? Es erscheint seltsam, einen Hinweis auf TABELLEN-Ebene zu verwenden, da es sich um ein internes Indizierungsproblem handelt - es handelt sich nur um eine Tabelle. Wird UPDLOCK, HOLDLOCK automatisch nur auf alle für diese Tabelle benötigten Indizes angewendet und erzwingt dadurch die Serialisierung?
Hier sind die Fragen:
UPDATE htt_action_log
SET status = 'ABORTED', CLOSED = GETUTCDATE()
WHERE transition_uuid = '{F53ADDDA-E46B-4726-66D8-D7B640B66597}'
AND status = 'OPEN';
Dieses eine X sperrt die Zeile im CI (in der Spalte CREATED) und versucht dann, das NCI zu sperren, das die Statusspalte enthält.
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)
Dieses eine U sperrt dieselbe NCI - für die verschachtelte Abfrage, denke ich, und sperrt dann das CI für das Update.
Somit erzeugt die Bestellung den Deadlock.
Die einfachste Lösung besteht darin, die beiden Abfragen zu zwingen, vollständig zu blockieren - dh zu serialisieren. Was ist der einfachste Weg, dies zu erzwingen? Fügen Sie einfach WITH (UPDLOCK, HOLDLOCK)
die Verweise auf die Tabelle hinzu (eine in der ersten und zwei in der zweiten).
DDL:
Hinweis: Der Client verfügt über mehr Indizes für diese Tabelle, die von diesem Update betroffen sein sollten, jedoch im Deadlock-Diagramm nicht erwähnt werden.
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]
quelle