Я столкнулся с проблемой в базе данных между двумя хранимыми процедурами, одна пытается обновить, а другая хочет удалить какой-то огромный объем данных.
Моя таблица Offer
содержит 50 миллионов строк (я не знаю хорошей практики, я очищаю данные).
Таблица содержит инкрементный идентификатор (не offer_id), который является первичным ключом с кластеризованным индексом на нем.
Xml_deadlock_report:
<event name="xml_deadlock_report" package="sqlserver" timestamp="2018-01-02T00:56:16.360Z">
<data name="xml_report">
<type name="xml" package="package0" />
<value>
<deadlock>
<victim-list>
<victimProcess id="process3697498" />
</victim-list>
<process-list>
<process id="process3697498" taskpriority="0" logused="127362200" waitresource="PAGE: 9:1:99977592 " waittime="6212" ownerId="32514985656" transactionname="DELETE" lasttranstarted="2018-01-02T01:55:56.853" XDES="0x902e53ed28" lockMode="IX" schedulerid="5" kpid="10104" status="suspended" spid="155" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-01-02T00:00:02.427" lastbatchcompleted="2018-01-02T00:00:02.427" lastattention="1900-01-01T00:00:00.427" clientapp="SQLAgent - TSQL JobStep (Job 0xAF5CC7B9127279438B52607063734954 : Step 1)" hostname="HB01-BOSQL-CL02" hostpid="5008" loginname="RUEDUCOMMERCE\hicham.boutaleb" isolationlevel="read committed (2)" xactid="32514985656" currentdb="9" lockTimeout="4294967295" clientoption1="671088928" clientoption2="128056">
<executionStack>
<frame procname="EchangesDb.dbo.PurgeGM2" line="433" stmtstart="57518" stmtend="57750" sqlhandle="0x03000900c9c6d33469f20e0158a8000001000000000000000000000000000000000000000000000000000000">
DELETE
TOP (100000)
OFFER
WHERE
ID IN (SELECT ID FROM #OFFERSTODELETE)
OPTION(MAXDOP 1)
</frame>
<frame procname="adhoc" line="1" sqlhandle="0x010009008b23cd0690ffbc006500000000000000000000000000000000000000000000000000000000000000">
Exec PurgeGM2 </frame>
</executionStack>
<inputbuf>
Exec PurgeGM2 </inputbuf>
</process>
<process id="process5b230c8" taskpriority="0" logused="183626528" waitresource="PAGE: 9:1:99056248 " waittime="2010" ownerId="32514934129" transactionname="user_transaction" lasttranstarted="2018-01-02T01:55:46.243" XDES="0xd0e49f16c0" lockMode="U" schedulerid="15" kpid="10684" status="suspended" spid="128" sbid="0" ecid="22" priority="0" trancount="0" lastbatchstarted="2018-01-02T01:55:46.240" lastbatchcompleted="2018-01-02T01:55:46.240" lastattention="1900-01-01T00:00:00.240" clientapp=".Net SqlClient Data Provider" hostname="HB01-BIZTALK01" hostpid="2620" isolationlevel="read committed (2)" xactid="32514934129" currentdb="9" lockTimeout="4294967295" clientoption1="673317152" clientoption2="128056">
<executionStack>
<frame procname="EchangesDb.dbo.offer_insert_diff" line="183" stmtstart="8450" stmtend="8780" sqlhandle="0x0300090048642c329947700146a8000001000000000000000000000000000000000000000000000000000000">
UPDATE o
SET tc_process_status = 0
FROM [dbo].[offer] AS o WITH(NOLOCK)
INNER JOIN Temp_OffersToMove AS t WITH(NOLOCK) ON (o.offer_id = t.offer_id) </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 9 Object Id = 841770056]
</inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="99977592" dbid="9" subresource="FULL" objectname="EchangesDb.dbo.offer" id="lock3d70957380" mode="U" associatedObjectId="72057595568062464">
<owner-list>
<owner id="process5b230c8" mode="U" />
</owner-list>
<waiter-list>
<waiter id="process3697498" mode="IX" requestType="wait" />
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="99056248" dbid="9" subresource="FULL" objectname="EchangesDb.dbo.offer" id="lock6d7712ab80" mode="IX" associatedObjectId="72057595568062464">
<owner-list>
<owner id="process3697498" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process5b230c8" mode="U" requestType="wait" />
</waiter-list>
</pagelock>
</resource-list>
</deadlock>
</value>
</data>
</event>
2 ответа
И спасибо всем за вашу помощь.
Моя проблема была решена с помощью Предложения Эрланда и некоторая дополнительная работа:
1) Уменьшите размер партии (найдите хороший порог, для меня 5000).
2) Установите для очистки низкий уровень deadlock_priority.
3) Добавить повтор для тупиковых ситуаций в очистке (для 1025 ошибок).
4) уменьшите размер моей временной таблицы, содержащей строки для удаления после каждой итерации (удалите верхние 5000 из порядка по идентификатору)
И теперь все работает нормально.
Огромное спасибо.
Не имеет значения, что Offer.Offer_Id
не является первичным ключом. Блокирует строки обложки, страницы или таблицы, но не столбцы. Если одно поле в таблице изменяется, вся строка блокируется как минимум.
Исходя из того, как это написано, я предполагаю, что ваша процедура удаления выполняет этот оператор:
DELETE TOP (100000) OFFER
WHERE ID IN (
SELECT ID
FROM #OFFERSTODELETE
)
OPTION (MAXDOP 1)
В каком-то цикле, возможно, с коммитами (и, возможно, контрольными точками) на каждой итерации, пока не будут удалены строки? А #OFFERSTODELETE
, вероятно, несколько миллионов строк?
Вы можете снизить вероятность возникновения взаимоблокировок, уменьшив количество строк, удаляемых при каждой итерации. Скажем, 100
или 500
. Это уменьшит количество блокировок, а также снизит вероятность повышения блокировок до блокировок страниц или таблиц. В целом, конечно, это займет больше времени, но зато будет легче. Также было бы неплохо запустить удаление в одночасье, если все ваши пользователи используют один часовой пояс, или (что еще лучше) во время запланированного простоя. Тогда вы могли бы потенциально снять ограничение MAXDOP
и не беспокоиться об использовании ЦП.
Помимо этого, на самом деле невозможно вносить какие-либо предложения, не просматривая каждую процедуру целиком. Возможно, вы сможете переписать две процедуры, чтобы они не блокировали друг друга. К сожалению, это не всегда возможно.
Также:
Моя таблица
Offer
содержит 50 миллионов строк (я не знаю хорошей практики, я очищаю данные).
В таблице такого размера нет ничего по сути . По правде говоря, он даже не особо большой. Если у вас хороший индекс кластеризации и вы всегда правильно фильтруете данные, вы не должны сильно влиять на производительность из-за размера таблицы. Пока вы выполняете обычную статистику и обслуживание индексов, у вас может не возникнуть никаких проблем.
Новые вопросы
sql-server
Microsoft SQL Server - это система управления реляционными базами данных (RDBMS). Используйте этот тег для всех выпусков SQL Server, включая Compact, Express, Azure, Fast-track, APS (ранее PDW) и Azure SQL DW. Не используйте этот тег для других типов СУБД (MySQL, PostgreSQL, Oracle и т. Д.). Не используйте этот тег для проблем, связанных с разработкой программного обеспечения и мобильных устройств, если только он не связан напрямую с базой данных.