Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
maxim83
Member

Откуда:
Сообщений: 5
Помогите пожалуйста прочитать понять суть происходящего по графу дедлока.
Выполняется простой UPDATE одной таблицы.
В дедлоке участвует только один ресурс - причем делается два одинаковых апдейта.
Индекс в таблице есть, обновление выполняется по первичному ключу.
Deadlock стабильно воспроизводится в рабочей системе.

Версия сервера - SQL 2008 R2


<deadlock-list>
<deadlock victim="process48d3b88">
<process-list>
<process id="process48d3b88" taskpriority="0" logused="404" waitresource="KEY: 10:72057594042580992 (2a00220ed90b)" waittime="4341" ownerId="108196770" transactionname="user_transaction" lasttranstarted="2012-12-12T16:57:41.797" XDES="0x8035b970" lockMode="X" schedulerid="3" kpid="7612"

status="suspended" spid="56" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2012-12-12T16:57:41.857" lastbatchcompleted="2012-12-12T16:57:41.847" clientapp=".Net SqlClient Data Provider" hostname="EIP" hostpid="5724" loginname="NT AUTHORITY\SYSTEM" isolationlevel="serializable (4)"

xactid="108196770" currentdb="10" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="120" stmtend="392" sqlhandle="0x0200000058dbc537adb6fac9fc8bd369cca7bc6ff2639ef4">
UPDATE [dbo].[Device]
SET [WstId] = @p2, [Size] = @p3, [ModifiedDate] = @p4
WHERE ([Id] = @p0) AND ([Version] = @p1) </frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(@p0 int,@p1 timestamp,@p2 int,@p3 int,@p4 datetime,@p5 int)UPDATE [dbo].[Device]
SET [WstId] = @p2, [Size] = @p3, [ModifiedDate] = @p4
WHERE ([Id] = @p0) AND ([Version] = @p1)

SELECT [t1].[Version]
FROM [dbo].[Device] AS [t1]
WHERE ((@@ROWCOUNT) > 0) AND ([t1].[Id] = @p5) </inputbuf>
</process>
<process id="process34f288" taskpriority="0" logused="404" waitresource="KEY: 10:72057594042580992 (2a00220ed90b)" waittime="4342" ownerId="108196769" transactionname="user_transaction" lasttranstarted="2012-12-12T16:57:41.797" XDES="0xb6da23b0" lockMode="U" schedulerid="1" kpid="6932"

status="suspended" spid="61" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2012-12-12T16:57:41.857" lastbatchcompleted="2012-12-12T16:57:41.843" clientapp=".Net SqlClient Data Provider" hostname="EIP" hostpid="5724" loginname="NT AUTHORITY\SYSTEM" isolationlevel="serializable (4)"

xactid="108196769" currentdb="10" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="120" stmtend="392" sqlhandle="0x0200000058dbc537adb6fac9fc8bd369cca7bc6ff2639ef4">
UPDATE [dbo].[Device]
SET [WstId] = @p2, [Size] = @p3, [ModifiedDate] = @p4
WHERE ([Id] = @p0) AND ([Version] = @p1) </frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(@p0 int,@p1 timestamp,@p2 int,@p3 int,@p4 datetime,@p5 int)UPDATE [dbo].[Device]
SET [WstId] = @p2, [Size] = @p3, [ModifiedDate] = @p4
WHERE ([Id] = @p0) AND ([Version] = @p1)

SELECT [t1].[Version]
FROM [dbo].[Device] AS [t1]
WHERE ((@@ROWCOUNT) > 0) AND ([t1].[Id] = @p5) </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594042580992" dbid="10" objectname="EIPDB.dbo.Device" indexname="PK_Device" id="locka28c1500" mode="U" associatedObjectId="72057594042580992">
<owner-list>
<owner id="process34f288" mode="S"/>
</owner-list>
<waiter-list>
<waiter id="process48d3b88" mode="X" requestType="convert"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594042580992" dbid="10" objectname="EIPDB.dbo.Device" indexname="PK_Device" id="locka28c1500" mode="U" associatedObjectId="72057594042580992">
<owner-list>
<owner id="process48d3b88" mode="U"/>
</owner-list>
<waiter-list>
<waiter id="process34f288" mode="U" requestType="convert"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
14 дек 12, 13:41    [13631597]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
Гость333
Member

Откуда:
Сообщений: 3683
maxim83,

Ресурс один, но один процесс пытается конвертировать S-блокировку до U-блокировки, а другой процесс — U-блокировку до X-блокировки. Покажите CREATE TABLE для таблицы Device.
14 дек 12, 14:10    [13631866]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
maxim83
Member

Откуда:
Сообщений: 5
Вот скрипт создания таблицы.
Про конвертацию я не понял как так получилось - что у одного процесса появилась S-lock, а у второго U.
Есть мнение, что это возникло из-за того, что уровень изоляции транзакций был выставлен в SERIALIZABLE

--DROP TABLE [dbo].[Device]

CREATE TABLE [dbo].[Device](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](500) NOT NULL,
[WstId] [int] NULL,
[TypeId] [int] NOT NULL,
[LocalId] [uniqueidentifier] NOT NULL,
[GlobalId] [uniqueidentifier] NOT NULL,
[PhysicalPath] [nvarchar](500) NULL,
[Size] [int] NULL,
[StateMask] [int] NOT NULL,
[ModifiedDate] [datetime] NULL,
[DeletedDate] [datetime] NULL,
[Version] [timestamp] NOT NULL,
CONSTRAINT [PK_Device] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO


/****** Object: Index [AK_Device_GlobalId_DeletedDate] Script Date: 12/14/2012 14:23:10 ******/
CREATE UNIQUE NONCLUSTERED INDEX [AK_Device_GlobalId_DeletedDate] ON [dbo].[Device]
(
[GlobalId] ASC,
[DeletedDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

/****** Object: Index [IX_Device_WstId] Script Date: 12/14/2012 14:23:10 ******/
CREATE NONCLUSTERED INDEX [IX_Device_WstId] ON [dbo].[Device]
(
[WstId] ASC,
[DeletedDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO


/****** Object: Index [IX_Device_WstId_TypeId] Script Date: 12/14/2012 14:23:10 ******/
CREATE NONCLUSTERED INDEX [IX_Device_WstId_TypeId] ON [dbo].[Device]
(
[WstId] ASC,
[TypeId] ASC,
[DeletedDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Device] WITH CHECK ADD CONSTRAINT [FK_Device_DeviceType] FOREIGN KEY([TypeId])
REFERENCES [dbo].[DeviceType] ([Id])
GO

ALTER TABLE [dbo].[Device] CHECK CONSTRAINT [FK_Device_DeviceType]
GO

ALTER TABLE [dbo].[Device] WITH CHECK ADD CONSTRAINT [FK_Device_Workstation] FOREIGN KEY([WstId])
REFERENCES [dbo].[Workstation] ([Id])
GO

ALTER TABLE [dbo].[Device] CHECK CONSTRAINT [FK_Device_Workstation]
GO
14 дек 12, 14:27    [13632037]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74930
План запросов покажите? Scanов нигде нет часом?
14 дек 12, 14:35    [13632106]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
maxim83
Member

Откуда:
Сообщений: 5
По плану запросов - ничего криминального: делается Clustered Index Seek по PK_Device - собственно поиск самой записи, потом тут
же Cluster Index Update (PK_Device (Id) - это кластерный индекс по Primary Key)

Ну и проверка внешнего ключа WstId - по связанной таблице - но тут тоже Clustered Index Seek из Workstation

К сожалению погонять на боевой БД не могу - дедлок прислал заказчик.
14 дек 12, 15:10    [13632445]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74930
maxim83,

А здесь SELECT что делает? Причем выбирается совсем другая строка.

UPDATE [dbo].[Device]
SET [WstId] = @p2, [Size] = @p3, [ModifiedDate] = @p4
WHERE ([Id] = @p0) AND ([Version] = @p1)

SELECT [t1].[Version]
FROM [dbo].[Device] AS [t1]
WHERE ((@@ROWCOUNT) > 0) AND ([t1].[Id] = @p5)


READ_COMMITED_SNAPSHOT я так понимаю не включена?
14 дек 12, 15:27    [13632648]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
Гость333
Member

Откуда:
Сообщений: 3683
maxim83,

Транзакция открывается на клиенте? С начала транзакции до представленного батча что-то происходит?
14 дек 12, 15:56    [13632892]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
maxim83
Member

Откуда:
Сообщений: 5
Для доступа к БД используется стандартный фреймворк из .NET - LINQ-TO-SQL - суть в том, что в случае успешного обновления
записи он сам перезачитывает новую версию записи - поле Version это timestamp. Таким образом гарантируется, что между транзакциям объект не был модифицирован другим пользователем.

В данном случае это одна и та же запись, т.к. @p0 = @p5.

READ_COMMITED_SNAPSHOT - это режим не включен. Но я там понимаю, его включение не поможет в случае уже используется ISOLATION LEVEL SERIALIZABLE?
14 дек 12, 15:58    [13632916]     Ответить | Цитировать Сообщить модератору
 Re: Помогите прочитать граф дедлока - очень простой - одна таблица, один ресурс => deadlock  [new]
maxim83
Member

Откуда:
Сообщений: 5
Гость333,

Поднял сейчас код приложения: судя по всему там 3 запроса.

Транзакция начинается и заканчивается на сервере приложения (.NET)

Идея такая - на сервер получает идентификатор станции WstId = @p0 и набор идентификаторов @p1..@pN на обновление.
Далее в одной транзакции делается последовательно:

1) Обновление статуса устройств на данной станции

UPDATE [Device] SET [StateMask] = 0 WHERE [WstId] = @p0 AND [DeletedDate] IS NULL


2) Далее сервер приложения извлекает массив устройств по их глобальным идентификаторам

SELECT * FROM Device WHERE GlobalId IN (@p1 ... @pN) AND [DeletedDate] IS NULL

для каждого найденного Device выполняется обновление


3) Для каждого найденного значения выполняется обновление - тот самый запрос UPDATE из графа дедлока
14 дек 12, 16:17    [13633099]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить