Как предотвратить "истечение тайм-аута запроса"? (Ошибка SQLNCLI11 '80040e31')

У меня есть соединение с базой данных MS SQL Server 2012 в классическом ASP (VBScript). Это моя строка соединения:

Provider=SQL Server Native Client 11.0;Server=localhost;
Database=databank;Uid=myuser;Pwd=mypassword;

Когда я выполняю эту команду SQL:

UPDATE [info] SET [stamp]='2014-03-18 01:00:02',
[data]='12533 characters goes here',
[saved]='2014-03-18 01:00:00',
[confirmed]=0,[ip]=0,[mode]=3,[rebuild]=0,
[updated]=1,[findable]=0 
WHERE [ID]=193246;

Я получаю следующую ошибку:

Microsoft SQL Server Native Client 11.0 
error '80040e31'
Query timeout expired   
/functions.asp, line 476

SQL-запрос довольно длинный, поле данных обновляется с 12533 ​​символами. Столбец идентификатора индексируется, поэтому поиск сообщения с идентификатором 193246 должен быть быстрым.

Когда я выполняю то же самое выражение SQL (скопированное и вставленное) в SQL Server Management Studio, оно завершается успешно в кратчайшие сроки. Нет проблем с тем, что когда-либо было. Таким образом, проблема с самим SQL не возникает. Я даже попытался использовать объект ADODB.Recordset и обновить его (без самозаписываемого SQL), но я все равно получаю ту же самую ошибку тайм-аута.

Если я перейду в "Инструменты" > "Параметры" > "Выполнение запросов" в Studio Management, я вижу, что таймаут выполнения установлен в 0 (бесконечный). В разделе "Инструменты" > "Параметры" > "Дизайнеры" я вижу, что тайм-аут транзакции установлен в 30 секунд, что должно быть достаточно большим, поскольку script и база данных находятся на одном компьютере ( "localhost" находится в строке подключения).

Что здесь происходит? Почему я могу выполнить SQL в Studio Management, но не в моем ASP-коде?


Изменить:. Пробовал настройку тайм-аута 30 секунд на вкладке "Дизайнеры" на 600 секунд, чтобы убедиться, но я все равно получаю ту же самую ошибку (происходит через 30 секунд загрузки страницы по btw).

Вот код, который я использую для выполнения SQL на странице ASP:

Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open "Provider=SQL Server Native Client 11.0;
Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;"
Conn.Execute "UPDATE [info] SET [stamp]='2014-03-18 01:00:02',
[data]='12533 characters goes here',[saved]='2014-03-18 01:00:00',
[confirmed]=0,[ip]=0,[mode]=3,[rebuild]=0,[updated]=1,[findable]=0 
WHERE [ID]=193246;"

Изменить 2: Используя Conn.CommandTimeout = 0, чтобы дать бесконечное время выполнения запроса, ничего не делает, он просто заставляет запрос выполняться вечно. Ждал 25 минут, и он все еще выполнялся.

Затем я попытался разделить SQL на два оператора SQL, длительное обновление данных в одном и других обновлениях в другом. Он по-прежнему не будет обновлять длинное поле данных, просто получил тайм-аут.

Я попробовал это с двумя дополнительными строками подключения:

Driver={SQL Server};Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;
Driver={SQL Server Native Client 11.0};Server=localhost;Database=databank;Uid=myuser;Pwd=mypassword;

Не работает. Я даже попытался изменить данные на 12533 ​​А, чтобы проверить, не вызвали ли фактические данные проблемы. Нет, та же проблема.

Затем я узнал что-то интересное: сначала я попытался выполнить короткий SQL, перед длинным обновлением поля данных. Он также получил исключение таймаута запроса...

Но почему? В нем так мало материала для обновления (весь оператор SQL составляет менее 200 символов). Будем дальше исследовать.


Изменить 3: Я думал, что это могло быть связано с логином, но я не нашел ничего, что выглядело бы неправильно. Я даже попытался изменить строку подключения для использования sa-account, но даже это не сработало, все еще получая "Истекло время ожидания запроса".

Это сводит меня с ума. Нет решения, нет обходного пути, и хуже всего нет идей!


Отредактируйте 4: Пошли в Инструменты > Параметры > Дизайнеры в Studio Management и отметили "Запретить сохранение изменений, требующих повторного создания таблицы". Он ничего не сделал.

Попробовал сменить тип данных столбца данных "данные" с "nvarchar (MAX)" на более низкий тип "ntext" (я отчаянно). Это не сработало.

Пробовал выполнить наименьшее изменение на почте, о которой я мог подумать:

UPDATE [info] SET [confirmed]=0 WHERE [ID]=193246;

Это установило бы бит столбца в значение false. Не работает. Я попытался выполнить тот же самый запрос в Management Studio, и он работал безупречно.

Бросьте мне несколько идей, если у вас их есть, потому что сейчас я бегаю по-настоящему.


Изменить 5:. Попробовали также следующую строку подключения:

Provider=SQLOLEDB.1;Password=mypassword;Persist Security Info=True;User ID=myuser;Initial Catalog=databank;Data Source=localhost

Не работает. Только попытался установить подтверждение на false, но все же получил тайм-аут.


Изменить 6: Теперь попытались обновить другое сообщение в той же таблице:

UPDATE [info] SET [confirmed]=0 WHERE [ID]=1;

Он также дал ошибку тайм-аута. Итак, теперь мы знаем, что это не сообщение специфическое.

Я могу обновлять сообщения в других таблицах в той же базе данных "базы данных" через ASP. Я также могу обновлять таблицы в других базах данных на localhost.

Может ли что-то сломаться с таблицей [info]? Я использовал мастер доступа MS для автоматического перемещения данных из Access в MS SQL Server 2012, он создал столбцы типа данных "ntext", и я вручную перешел и изменил это на "nvarchar (MAX)", поскольку ntext устарел. Разве что-то сломалось? Это потребовало от меня повторного создания таблицы, когда я изменил тип данных.

Мне нужно немного поспать, но я обязательно вернусь завтра, если кто-нибудь ответит мне. Пожалуйста, сделайте это, даже если у вас есть только что-то обнадеживающее.


Изменить 7:Быстрое редактирование перед сном. Пытался определить провайдера как "SQLNCLI11" в строке соединения (используя имя DLL вместо фактического имени поставщика). Это не имеет значения. Соединение создается так же хорошо, но тайм-аут все еще происходит.

Также я не использую MS SQL Server 2012 Express (насколько я знаю, "Экспресс" нигде не упоминался во время установки). Это полная вещь.

Если это помогает, здесь информация "Справка" > "О...", предоставленная Management Studio:

Microsoft SQL Server Management Studio: 11.0.2100.60  
Microsoft Analysis Services Client Tools: 11.0.2100.60  
Microsoft Data Access Components (MDAC): 6.3.9600.16384  
Microsoft MSXML: 3.0 5.0 6.0   
Microsoft Internet Explorer: 9.11.9600.16521  
Microsoft .NET Framework: 4.0.30319.34011  
Operating System: 6.3.9600

Редактировать 8 (также известный как "программисты никогда не спят" ):

После некоторых попыток я попытался закрыть соединение с базой данных и снова открыть его перед выполнением операторов SQL. Это сработало неожиданно. Что...?

У меня был код внутри подпрограммы, и выяснилось, что за его пределами сообщение, которое я пытался обновить, уже было открыто! Поэтому причиной таймаута было то, что сообщение или целая таблица заблокировано тем же самым соединением, которое пыталось обновить его. Таким образом, соединение (или поток процессора) ожидало блокировки, которая никогда не будет разблокирована.

Ненавидите его, когда он окажется таким простым после того, как вы так стараетесь.

Сообщение было открыто вне подпрограммы с помощью этого простого кода:

Set RecSet = Conn.Execute("SELECT etc")

Я просто добавил следующее, прежде чем вызывать подпрограмму.

RecSet.Close
Set RecSet = Nothing

Причина, по которой это никогда не приходило мне в голову, просто потому, что это было разрешено в MS Access, но теперь я изменился на MS SQL Server, и это было не так мило (или неаккуратно, скорее). Созданный RecSet by Conn.Execute() никогда ранее не создавал заблокированную запись в базе данных, но теперь это внезапно. Не слишком странно, поскольку строка подключения и фактическая база данных изменились.

Я надеюсь, что этот пост спасет кого-то еще от головной боли, если вы перейдете с MS Access на MS SQL Server. Хотя я не могу себе представить, что в настоящее время многие пользователи Access остались в мире.

Ответ 1

Оказывается, что сообщение (или, вернее, целая таблица) было заблокировано тем же соединением, которое я пытался обновить.

У меня был открытый набор записей, который был создан:

Set RecSet = Conn.Execute()

Этот тип записей должен быть доступен только для чтения, и когда я использовал MS Access в качестве базы данных, он ничего не блокировал. Но, по-видимому, этот набор записей блокировал что-то на MS SQL Server 2012, потому что когда я добавил эти строки кода перед выполнением инструкции UPDATE SQL...

RecSet.Close
Set RecSet = Nothing

... все работало нормально.

Итак, нижняя строка должна быть осторожна с открытыми наборами записей - даже если они доступны только для чтения, они могут заблокировать вашу таблицу от обновлений.