У меня простая таблица с 6 столбцами. В большинстве случаев любые операторы вставки в него работают нормально, но время от времени я получаю исключение тайм-аута БД: Истекло время ожидания. Время ожидания истекло до завершения операции или сервер не отвечает. Заявление было прекращено.
Тайм-аут установлен на 10 секунд.
Я должен упомянуть, что я использую NHibernate и что оператор также включает "select SCOPE_IDENTITY ()" сразу после самой вставки.
Я подумал, что таблица была заблокирована или что-то в этом роде, но в то время не было других операторов, работающих на этой таблице.
Все вставки очень простые, в профилировщике sql все выглядит нормально, в таблице нет индексов, кроме PK (заполненность страницы: 98,57%).
Есть идеи, что мне искать?
Спасибо.


посмотрите на фрагментацию таблицы, вы можете получить разбиение страницы из-за этого
no other statements running on that table at that time.
А как насчет операторов, выполняемых с другими таблицами как часть транзакции? Это может оставить замки в таблице проблем.
Также проверьте, не происходит ли рост файла журнала или файла данных в то время, если вы используете SQL2005, это будет отображаться в журналах ошибок SQL.
примерно так: 0: начать транзакцию; 1: обновить одну запись в таблице проблем (выполняется быстро); 2: обновить какую-то другую таблицу (занимает много времени); 3: таблица проблем фиксации будет заблокирована до шага 3; если другое задание пытается обновить заблокированную запись, оно будет ждать.
Я думаю, что ваш наиболее вероятный виновник - блокировка от другой транзакции (или, может быть, от триггера или чего-то еще за кулисами).
Самый простой способ узнать об этом - запустить INSERT и, пока он завис, запустить EXEC SP_WHO2 в другом окне на том же сервере. В нем будут перечислены все текущие операции с базой данных и будет столбец BLK, который покажет вам, заблокированы ли какие-либо процессы в данный момент. Проверьте SPID вашего зависшего соединения, чтобы увидеть, есть ли что-нибудь в столбце BLK, и если да, то это процесс, который вас блокирует.
Даже если вы не думаете, что выполняются какие-либо другие операторы, единственный способ узнать наверняка - это перечислить текущие транзакции, используя такой SP.
Что, если тайм-аут случается время от времени, я не могу «поймать» время, когда это произойдет, чтобы запустить команды отладки?
как остановить блокирующий процесс?
Я полагаю, если бы ваш тайм-аут составлял 10 секунд, вы могли бы запустить SP_WHO2 (см. Другие ответы) через 8 или 9 секунд и посмотреть, поймал ли он что-то. Это может быть сложно реализовать, но это может быть единственный способ. Конечно, если это удастся, вы бы отменили его, прежде чем он начался.
Может быть, стол долго растет.
Если у вас есть таблица, настроенная на большой рост, и у вас не включена мгновенная инициализация файла, то время от времени запрос, безусловно, может отключаться по таймауту.
Проверьте этот беспорядок: MSDN
autogrowth установлен на 1 МБ, может ли выделение 1 МБ занять так много времени?
@meidan нет, это не займет так много времени, но я бы изменил его, чтобы он увеличивался в гораздо более крупных кусках, или со временем вы получите очень фрагментированную файловую систему, если она будет постоянно расти. по умолчанию - 10%, и это хорошо работает для большинства, кроме очень больших dbs.
@Eam - танки! это очень важно при вставке больших объектов
У нашего QA было несколько подключений к Excel, которые возвращали большие наборы результатов, эти запросы на некоторое время были приостановлены с WaitType ASYNC_NETWORK_IO. В это время истекло время ожидания всех остальных запросов, так что конкретная вставка не имела к этому никакого отношения.
Этот вопрос кажется хорошим местом для фрагмента кода, который я использовал, чтобы увидеть фактический текст SQL заблокированных и блокирующих запросов.
В приведенном ниже фрагменте используется соглашение, согласно которому SP_WHO2 возвращает "." текст для BlockedBy для неблокированных запросов, и поэтому он их отфильтровывает и возвращает текст SQL оставшихся запросов (как "жертв", так и "виновников"):
--prepare a table so that we can filter out sp_who2 results
DECLARE @who TABLE(BlockedId INT,
Status VARCHAR(MAX),
LOGIN VARCHAR(MAX),
HostName VARCHAR(MAX),
BlockedById VARCHAR(MAX),
DBName VARCHAR(MAX),
Command VARCHAR(MAX),
CPUTime INT,
DiskIO INT,
LastBatch VARCHAR(MAX),
ProgramName VARCHAR(MAX),
SPID_1 INT,
REQUESTID INT)
INSERT INTO @who EXEC sp_who2
--select the blocked and blocking queries (if any) as SQL text
SELECT
(
SELECT TEXT
FROM sys.dm_exec_sql_text(
(SELECT handle
FROM (
SELECT CAST(sql_handle AS VARBINARY(128)) AS handle
FROM sys.sysprocesses WHERE spid = BlockedId
) query)
)
) AS 'Blocked Query (Victim)',
(
SELECT TEXT
FROM sys.dm_exec_sql_text(
(SELECT handle
FROM (
SELECT CAST(sql_handle AS VARBINARY(128)) AS handle
FROM sys.sysprocesses WHERE spid = BlockedById
) query)
)
) AS 'Blocking Query (Culprit)'
FROM @who
WHERE BlockedById != ' .'
Крысы. В SQL 2000 у меня неправильный синтаксис рядом с 'MAX', EXECUTE нельзя использовать в качестве источника при вставке в переменную таблицы и т. д. Какая версия SQL требуется для этого скрипта? Он работает в SQL 2008, но эта db не моя проблема.
Вы пробовали использовать временную таблицу вместо табличной переменной?
Извиняюсь за совершенно бесполезный комментарий, но ... Молодец этот человек :) Это сценарий для зала славы. Помог мне решить проблему, которая долгое время преследовала одну из наших систем. +1000
на самом деле транзакция вставляется в 3 таблицы, но как она могла заблокировать проблемную таблицу?