Спящий SPID блокирует другие транзакции

16

У меня действительно есть проблемы с отслеживанием некоторых блокировок, которые мы испытываем.

Статус SPID корневого блокирующего - «спящий», cmd - «AWAITING COMMAND» и « sqltextis» SET TRANSACTION ISOLATION LEVEL READ COMMITTED.

Когда я просматриваю отчет «Количество транзакций по количеству заблокированных транзакций», оператор блокирующего SQL имеет вид «-».

Я выполнил трассировку SQL и, когда происходит блокировка, отслеживает корневой блокирующий SPID, но это ни к чему меня не привело. Последний оператор трассировки такой же, как указано sqltextвыше SET TRANSACTION ISOLATION LEVEL READ COMMITTED.

Я проверил все связанные хранимые процедуры, которые я могу найти, чтобы убедиться, что они имеют операторы TRY / CATCH BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN (мы используем хранимые процедуры для всего, поэтому не выполняются отдельные операторы). Эта проблема только начала возникать в течение последних 24 часов, и никто не утверждает, что внес какие-либо изменения в систему.

Решение: одна из наших редко используемых хранимых процедур имела ошибку со вставкой (количество столбцов не совпадало), но мы все еще не уверены в том, что именно происходит.

При просмотре всей информации о трассировке оператор EXEC для этой хранимой процедуры иногда показывался, но НИКОГДА непосредственно перед тем, как BLOCK происходил с блокирующим SPID. Казалось, что когда он начал блокировать, трассировка не записывала его выполнение (или какие-либо операторы внутри него). Однако бывают случаи, когда трассировка записывала свое выполнение, и блокировка не происходила.

Отчет об ошибке хранимой процедуры был получен от пользователя, и я смог найти несколько операторов EXEC в трассировках и запустить их в SSMS. Ни разу, когда я запускал их, у нас не было никаких блокировок или они зависали. Они работали как ожидалось (блок catch сработал и откатил транзакцию после ошибки). После исправления хранимой процедуры мы больше не видели проблему.

штифтик
источник
Я предполагаю, что имя хоста блокирующего SPID вообще не помогло?
Джон Зигель
Нет, это всего лишь IP-адрес одного из наших веб-серверов ... У нас есть еще одна идея изменить каждое имя входа SQL для каждого вызова SPROC в процессе входа в систему / регистрации (что, по нашему мнению, является причиной возникновения ошибки) на отдельное имя пользователя, которое может помогите нам определить, какой SPROC может быть причиной блокировки.
Брэд
1
TRY / CATCH не будет отлавливать ошибки компиляции, и неправильная вставка столбца будет такой ошибкой компиляции. Это также никогда не вызовет многие события XX: Completed profiler.
Ремус Русану
1
Это на самом деле не ошибка компиляции в этом случае, потому что гениальный разработчик использовал INSERT INTO [таблица] SELECT * из [othertable] и не был пойман в одноранговой сети. Я запускал SPROC on Development 1000 раз из ColdFusion в 3 одновременных сеанса, и он никогда не оставлял открытой транзакцию, как это было в Production.
Брэд

Ответы:

10

Из комментариев я предполагаю, что у вас был тайм-аут команды на стороне клиента, который прервал SQL-запрос. Это не отменяет транзакцию, потому что соединение остается открытым на SQL Server из-за пула соединений.

Итак, вам нужно использовать SET XACT_ABORT ON или добавить некоторый код отката клиента

См. Тайм-аут транзакции SQL Server для всех подробностей

ГБН
источник
Все наши SPROC содержат блоки TRY / CATCH и операторы BEGIN TRAN / COMMIT TRAN / ROLLBACK TRAN, ROLLBACK находится в CATCH. Будет ли XACT_ABORT иметь эффект?
Брэд
@Brad: да. Смотрите мою ссылку. Блок захвата не срабатывает в CommandTimeout
gbn
ГБН: Спасибо. Я все еще в замешательстве. Наши соединения никогда не останавливаются (0). Таким образом, вы говорите, что если мы повторно используем соединения, и соединение запускает SPROC с ошибкой (которая имеет блоки TRY / CATCH и TRAN), оно каким-то образом никогда не сможет запустить ROLLBACK в блоке CATCH, блокируя таким образом таблицы и сохраняя транзакцию. открытый? Это не имеет смысла для меня.
Брэд
@Brad: SPROC с ошибкой попадет в блок CATCH. Я не сказал иначе или иначе. Но моя ссылка говорит, что происходит, если у вас есть CommandTimeout, который отличается от ConnectionTimeout. Клиент говорит «прервать», и SQL Server останавливает обработку. Ergo, блок CATCH, откат или фиксация никогда не
выполняются
Я не думаю, что мы указали CommandTimeout. Все наши хранимые процедуры тестируются с использованием sqlstress и должны выполнять менее 1000 мс при 10 пользователях 10 итераций (как минимум). Я все еще очень озадачен тем, что произошло, но я обновляю вопрос тем, в чем мы обнаружили проблему.
Брэд
9

Используйте most_recent_sql_handle в sys.dm_exec_connections, чтобы увидеть последний выполненный оператор.

SELECT  t.text,
        QUOTENAME(OBJECT_SCHEMA_NAME(t.objectid, t.dbid)) + '.'
        + QUOTENAME(OBJECT_NAME(t.objectid, t.dbid)) proc_name,
        c.connect_time,
        s.last_request_start_time,
        s.last_request_end_time,
        s.status
FROM    sys.dm_exec_connections c
JOIN    sys.dm_exec_sessions s
        ON c.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(c.most_recent_sql_handle) t
WHERE   c.session_id = 72;--your blocking spid

Также проверьте, есть ли открытые транзакции для этого спида

SELECT  st.transaction_id,
        at.name,
        at.transaction_begin_time,
        at.transaction_state,
        at.transaction_status
FROM    sys.dm_tran_session_transactions st
JOIN    sys.dm_tran_active_transactions at
        ON st.transaction_id = at.transaction_id
WHERE   st.session_id = 72;--your blocking spid
Себастьян Майн
источник
Вы также можете использовать, DBCC INPUTBUFFER(spid)чтобы увидеть последний выполненный SQL.
Майк Фал
Я использовал все это, и последняя команда - это то, что я положил в своем первоначальном посте: SET TRANSACTION ISOLATION LEVEL READ COMMITTED. Я также запустил DBCC OPENTRAN и вижу, что есть открытая транзакция для блокирующего PID.
Брэд
Мой первый выбор также дает вам имя процедуры, если оператор действительно является частью процедуры.
Себастьян Майн
Уверяю вас, мы не используем adhoc-запросы от наших веб-серверов, и когда я запускаю этот первый запрос, даже без предложения WHERE, я получаю именованный SPROC только для нескольких сеансов SQL, остальная часть этого столбца равна NULL.
Брэд
Я замечаю, что у меня есть тонны сеансов с надписью «УСТАНОВИТЬ УРОВЕНЬ ИЗОЛЯЦИИ СДЕЛКИ СДЕЛКИ», и все они из ColdFusion (основной сценарий, используемый на наших веб-серверах). Возможно, ColdFusion при простое выдает этот оператор для удержания открытого соединения (так как он установлен для того, чтобы соединения оставались открытыми).
Брэд
4

Вы пробовали использовать sp_whoisactive Адама Мачаника ? Есть возможность получить внешнюю команду, чтобы увидеть, действительно ли она находится внутри proc. Возможно, приложение удерживает транзакцию открытой, а не фиксирует ее. Попробуйте посмотреть на DBCC OPENTRAN .

Эрик Хамфри - Лотсхелп
источник
Спасибо за DBCC OPENTRAN. Это говорит мне, что блокирующий PID имеет открытую транзакцию, но больше подробностей нет. sp_whoisactive возвращает ту же информацию о заблокированном процессе, которую я смог получить самостоятельно. По-прежнему нет подробностей о том, что происходит, кроме «УСТАНОВЛЕНО УРОВЕНЬ УРОВНЯ ИЗОЛЯЦИИ СДЕЛКИ»
Брэд,