#sql-server #sql-server-2008 #debugging #windbg #memory-dump
#sql-server #sql-server-2008 #отладка #windbg #дамп памяти
Вопрос:
Окружающая среда:
Sql server 2008 r2
Windows 7 64 бит
Windbg 64 бит
Что я уже знаю
-
Я могу найти sql stmts в этих транзакциях, запустив трассировку профилировщика на стороне сервера и остановив ее, как только возникнет взаимоблокировка. А затем выполнить поиск идентификатора транзакции в файлах трассировки. Но это метод грубой силы, и его не всегда можно выполнить в производственной среде.
-
Я знаю, что должен отправить дамп памяти в Microsoft и получить, а затем проанализировать его. Но я хочу найти наш, если есть какая-либо надежда решить эту проблему без частных символов.
Проблема:
Я создаю дамп памяти, используя расширенные события в sql server, когда 2 транзакции взаимоблокировки (событие lock_deadlock).
Я вручную создаю этот сценарий взаимоблокировки через management Studio. Допустим, 1 из заблокированных xaction содержит 2 оператора sql.
begin tran
update tabl1 ... -- sql stmt 1
go
update tabl2 .. -- sql stmt 2
Теперь я нахожу этот поток в своем дампе памяти, и я могу найти только мой sql stmt 2, т.е. «обновить таблицу 2».
Могу ли я в любом случае просмотреть все sql stmt, которые поток выполнил в xaction, т.Е. в нашем случае «обновить таблицу 1 ..»?
Я хочу знать, что поток выполнял ранее в той же транзакции. Поскольку это xaction еще не зафиксировано во время дампа, значения должны быть где-то в памяти потока.
Пожалуйста, дайте мне знать, если я здесь не понимаю. Я некоторое время занимался этой проблемой, и я хочу знать, возможно ли это или нет.
ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ
Справочная информация:
у нас есть среда тестирования производительности, где мы проводим 12-часовые нагрузочные тесты. На следующее утро мы анализируем и обнаруживаем тупик. Приложение выполняет 7-8 операторов dml в транзакции (мы используем hibernate ). Поскольку sys.dm_exec_sql_text based даст результат, только если он находится в кэше, мы не получим весь набор операторов dml, поскольку мы анализируем его на следующий день (ps: я даже не пробовал это, когда мне сообщили о проблеме через 1 день)
Как мы решили эту проблему сегодня:
1. Настройка трассировки на стороне сервера
2. Настройка уведомления о событии, которое срабатывает при взаимоблокировке, и вызов sp, который останавливает трассировку.
3. Из расширенного отчета xml или профилировщика событий мы находим идентификатор транзакции и просматриваем прошлые операторы, соответствующие ему.
Как я думал, я мог бы решить эту проблему:
1. Вызвать дамп памяти при расширенном событии «lock_deadlock» с включенным системным идентификатором.
2. Каким-то образом попытайтесь найти историю в потоке, соответствующем системному идентификатору.
Почему дамп памяти:
потому что эта настройка окажет наименьшее влияние, если мне придется делать это на производстве.
Ответ №1:
Вы переусердствовали с этим. Я не утверждаю, что знаю все сложные детали памяти потока, но у него нет причин сохранять последний выполненный оператор локальным, он не нужен для выполнения отката транзакции, что выполняется с использованием записей журнала из журнала транзакций, если это необходимо. Все, что вам нужно для определения причины взаимоблокировки, уже содержится в XML-графе взаимоблокировки. Вам определенно не нужен дамп памяти, чтобы понять это. Стек выполнения TSQL для каждого из процессов содержится в элементе под процессом. Например:
<process-list>
<process id="process807b6bc8" taskpriority="0" logused="0" waitresource="KEY: 14:72057594038845440 (1a39e6095155)" waittime="4739" ownerId="163539" transactionname="INSERT EXEC" lasttranstarted="2011-10-05T12:29:22.580" XDES="0x82b318b0" lockMode="S" schedulerid="2" kpid="1764" status="suspended" spid="57" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2011-10-05T12:29:04.563" lastbatchcompleted="2011-10-05T12:29:04.563" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SQL2K8R2-IE2" hostpid="3736" loginname="SQLSKILLSDEMOSadministrator" isolationlevel="read committed (2)" xactid="163539" currentdb="14" lockTimeout="4294967295" clientoption1="673187936" clientoption2="390200">
<executionStack>
<frame procname="" line="3" stmtstart="118" stmtend="284" sqlhandle="0x03000e0020c96c7ef2b3cd00739f00000100000000000000" />
<frame procname="" line="3" stmtstart="50" stmtend="146" sqlhandle="0x02000000e00b66366c680fabe2322acbad592a896dcab9cb" />
</executionStack>
<inputbuf>
WHILE (1=1)
BEGIN
INSERT INTO #t1 EXEC BookmarkLookupSelect 4
TRUNCATE TABLE #t1
END
</inputbuf>
</process>
<process id="process807b7288" taskpriority="0" logused="228" waitresource="KEY: 14:72057594038910976 (e5b3d7e750dd)" waittime="4742" ownerId="163545" transactionname="UPDATE" lasttranstarted="2011-10-05T12:29:22.587" XDES="0x82b6f950" lockMode="X" schedulerid="2" kpid="12" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2011-10-05T12:29:10.607" lastbatchcompleted="2011-10-05T12:29:10.600" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SQL2K8R2-IE2" hostpid="3736" loginname="SQLSKILLSDEMOSadministrator" isolationlevel="read committed (2)" xactid="163545" currentdb="14" lockTimeout="4294967295" clientoption1="673187936" clientoption2="390200">
<executionStack>
<frame procname="" line="4" stmtstart="120" stmtend="262" sqlhandle="0x03000e0059ed607ff3b3cd00739f00000100000000000000" />
<frame procname="" line="4" stmtstart="82" stmtend="138" sqlhandle="0x020000002a7093322fbd674049d04f1dc0f3257646c4514b" />
</executionStack>
<inputbuf>
SET NOCOUNT ON
WHILE (1=1)
BEGIN
EXEC BookmarkLookupUpdate 4
END
</inputbuf>
</process>
</process-list>
Все, что вам нужно сделать, это взять информацию о sqlhandle и смещении из фреймов, и вы можете получить инструкции в стеке TSQL обратно, используя sys.dm_exec_sql_text() . Вы не сможете этого сделать, если пытаетесь вручную выполнять отдельные операторы по одному, чтобы вызвать взаимоблокировку, поскольку в каждом стеке будет только один оператор, который вы выполнили в нем.
ОБНОВЛЕНИЕ ИЗ ДОПОЛНИТЕЛЬНОЙ ИНФОРМАЦИИ:
Альтернативное использование уведомлений о событиях с внутренней активацией очереди для сбора дополнительной информации — лучший способ сделать то, что вы хотите, и это будет намного дешевле, чем выполнение дампа памяти. Хранимая процедура активации выполняется для уведомления о событии для асинхронного сбора данных, где дамп памяти выполняется синхронно в потоке запуска в расширенных событиях как действие.
Комментарии:
1. Я просмотрел дамп, используя .foreach (obj {s -[1]u 0 l?fffffff «update»}) {.printf » n%mu»,$ {obj}} и я смог найти 2-й sql stmt, но не первый. Спасибо за вашу помощь, Джонатан.