Поиск и устранение неисправностей в SQL Server 2008
Мой веб-сайт, похоже, не обрабатывает большое количество посетителей, я считаю, потому что сервер слишком прост.
2 часа назад на моем сайте было много хитов, и я заметил, что произошло 3 ошибки взаимоблокировки, ошибка:
System.Data.SqlClient.SqlException: Транзакция (идентификатор процесса 58) была заблокирована при блокировке ресурсов другим процессом и была выбрана в качестве жертвы взаимоблокировки. Перезапустите транзакцию.
Я не уверен, почему это произошло... Посмотрев на трассировку стека, я понял, что это произошло с запросом select.
Кто-нибудь знает, что может быть причиной этой ошибки?
Сервер работает под управлением Windows 2008 и Sql Server 2008.
Ответы
Ответ 1
Writes будет блокировать чтение на SQL Server, если только вы не включили управление версиями строк. Вы должны использовать хранимую процедуру sp_who2
и трассировку SQL Profiler. sp_who2
расскажет вам, какие процессы блокируют, и какой профилировщик расскажет вам, что последний оператор был для процесса блокировки.
Ответ 2
SQL Server 2008 имеет несколько способов идентификации процессов и запросов, связанных с тупиком.
-
Если взаимоблокировки легко воспроизводить, частота выше, и вы можете профилировать SQL-сервер (у вас есть доступ и производительность на сервере, когда профилировщик включен) с использованием SQL Profiler даст вам хороший графический вид тупика.
На этой странице есть вся информация, необходимая для использования кривых взаимоблокировки
http://sqlmag.com/database-performance-tuning/gathering-deadlock-information-deadlock-graph
-
Большая часть времени, воспроизводящая взаимоблокировки, является сложной, или они происходят в производственной среде, где мы не хотим прикреплять к ней Profiler и влиять на производительность.
Я бы использовал этот запрос, чтобы получить взаимоблокировки:
SELECT
xed.value('@timestamp', 'datetime') as Creation_Date,
xed.query('.') AS Extend_Event
FROM
(
SELECT CAST([target_data] AS XML) AS Target_Data
FROM sys.dm_xe_session_targets AS xt
INNER JOIN sys.dm_xe_sessions AS xs
ON xs.address = xt.event_session_address
WHERE xs.name = N'system_health'
AND xt.target_name = N'ring_buffer'
) AS XML_Data
CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xed)
ORDER BY Creation_Date DESC
Я бы не пошел в направлении использования (NOLOCK), чтобы исправить взаимоблокировки. Это скользкий склон и скрытие исходной проблемы.
Ответ 3
Если вы не против грязных чтений, вы можете попробовать положить (NOLOCK) после имен таблиц в свои запросы SELECT. Компромисс здесь заключается в том, что вам не гарантируются самые современные данные, поскольку инструкции UPDATE и INSERT, выполняемые в настоящее время, игнорируются.
Обычно это не большая часть поезда, поскольку большинство систем читают гораздо больше, чем они обновляют/вставляют, но, очевидно, это зависит от характера вашего приложения.
Альтернативно посмотрите http://www.sql-server-performance.com/tips/deadlocks_p1.aspx