Исключение времени ожидания соединения для запроса с использованием ADO.Net
обновление: похоже, что запрос не выдает таймаут. Время соединения истекает.
Это пример кода для выполнения запросов. Иногда при выполнении трудоемких запросов он выдает исключение timeout.
Я не может использовать любой из этих методов: 1) увеличить время ожидания. 2) Запустите его асинхронно с обратным вызовом. Это должно выполняться синхронно.
пожалуйста, предложите любой другой методики, чтобы держать соединение живое при выполнении трудоемкого запроса?
private static void CreateCommand(string queryString,
string connectionString)
{
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
}
16 ответов
поскольку вы используете ExecuteNonQuery, который не возвращает строк, вы можете попробовать этот подход на основе опроса. Он выполняет запрос в asyc-манере (без обратного вызова) но приложение будет ждать (внутри цикла while), пока запрос завершится. От MSDN. Это должно решить проблему ожидания. Пожалуйста, попробуйте.
но я согласен с другими, что вы должны больше думать об оптимизации запроса для выполнения менее 30 секунд.
IAsyncResult result = command.BeginExecuteNonQuery();
int count = 0;
while (!result.IsCompleted)
{
Console.WriteLine("Waiting ({0})", count++);
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Command complete. Affected {0} rows.",
command.EndExecuteNonQuery(result));
вы должны сначала проверить свой запрос, чтобы увидеть, оптимизирован ли он, и он каким-то образом не работает на отсутствующих индексах. 30 секунд отводится для большинства запросов, даже на больших базах данных, если они правильно настроены. Если у вас есть твердое доказательство, используя план запроса, что запрос не может быть выполнен быстрее, чем это, то вы должны увеличить тайм-аут, нет другого способа сохранить соединение, это цель тайм-аута для прекращения соединения, если запрос не завершается в это время.
Я должен согласиться с черепахой.
У вас есть несколько вариантов, как получить ваше время вниз. Во-первых, если ваша компания использует DBAs, я бы рекомендовал запросить у них предложения.
Если это не вариант, или если вы хотите попробовать некоторые другие вещи, во-первых здесь три основных варианта:
- разбейте запрос на компоненты, которые работают по таймауту. Это, наверное, самое простое.
- измените запрос для оптимизации пути доступа через базу данных (как правило: попадание в индекс как можно ближе)
- изменить или добавить индексы, чтобы повлиять на путь к вашему запросу.
Если вы ограничены от использования процесса по умолчанию изменения значения тайм-аута, вам, скорее всего, придется сделать намного больше работы. На ум приходят следующие варианты
- проверьте с помощью DBA и другого обзора кода, что вы действительно оптимизировали запрос как можно лучше
- работа над базовой структурой БД, чтобы увидеть, есть ли какой-либо выигрыш, который вы можете получить на стороне БД, создавая/изменяя idex(ы).
- разделить его на несколько части, даже если это означает выполнение процедур с несколькими возвращаемыми параметрами, которые просто вызывают другой параметр. (Эта опция не элегантна, и, честно говоря, если ваш код действительно займет столько времени, я бы пошел в управление и повторно обсудил 30-секундный тайм-аут)
недавно у нас была аналогичная проблема в базе данных SQL Server 2000.
во время запроса запустите этот запрос в главной базе данных на сервере БД и посмотрите, есть ли какие-либо блокировки, которые вы должны устранить:
select
spid,
db_name(sp.dbid) as DBname,
blocked as BlockedBy,
waittime as WaitInMs,
lastwaittype,
waitresource,
cpu,
physical_io,
memusage,
loginame,
login_time,
last_batch,
hostname,
sql_handle
from sysprocesses sp
where (waittype > 0 and spid > 49) or spid in (select blocked from sysprocesses where blocked > 0)
SQL Server Management Studio 2008 также содержит очень классный монитор активности, который позволяет видеть работоспособность базы данных во время запроса.
в нашем случае это была блокировка networkio, которая занимала базу данных. Это было какое-то наследие VB код, который не отключил его результирующий набор достаточно быстро.
Если вам запрещено использовать функции API доступа к данным, чтобы запрос длился более 30 секунд, нам нужно увидеть SQL.
увеличения представления, котор нужно сделать путем оптимизировать пользу ADO.NET незначительны по сравнению с преимуществами оптимизации SQL.
и вы уже используете наиболее эффективный метод выполнения SQL. Другие методы будут умственно медленнее (хотя, если вы сделали быстрый поиск ваших строк и некоторых очень медленная обработка на стороне клиента с помощью наборов данных, вы можете получить начальное извлечение менее чем за 30 секунд, но я сомневаюсь в этом.)
Если бы мы знали, Если вы делаете вставки, то, возможно, вы должны использовать bulk insert. Но мы не знаем содержание вашего sql.
это уродливый хак, но может помочь решить вашу проблему временно, пока вы не сможете исправить реальную проблему
private static void CreateCommand(string queryString,string connectionString)
{
int maxRetries = 3;
int retries = 0;
while(true)
{
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
break;
}
catch (SqlException se)
{
if (se.Message.IndexOf("Timeout", StringComparison.InvariantCultureIgnoreCase) == -1)
throw; //not a timeout
if (retries >= maxRetries)
throw new Exception( String.Format("Timedout {0} Times", retries),se);
//or break to throw no error
retries++;
}
}
}
command.CommandTimeout *= 2;
это удвоит время ожидания по умолчанию, которое составляет 30 секунд.
или поместите значение CommandTimeout в файл конфигурации, чтобы вы могли настроить его по мере необходимости без перекомпиляции.
вы должны разбить свой запрос на несколько блоков, каждый из которых выполняется в течение периода ожидания.
Если вы абсолютно не можете увеличить тайм-аут, ваш единственный вариант-уменьшить время выполнения запроса в течение 30-секундного тайм-аута по умолчанию.
Я, как правило, не люблю увеличивать тайм-аут соединения/команды, так как в моем уме это было бы вопросом ухода за симптомом, а не проблемой
вы думали о том, чтобы разбить запрос на несколько меньших кусков?
кроме того, вы выполнили свой запрос против помощника по настройке ядра СУБД в:
Management Studio > Инструменты > Помощник По Настройке Ядра СУБД
наконец, можем ли мы взглянуть на сам запрос?
ура
вы пытались обернуть свой sql внутри хранимой процедуры, они, похоже, имеют лучшее управление памятью. Видели тайм-ауты, как это раньше в инструкции plan sql с внутренними запросами с использованием классического ADO. т. е. выберите * from (select ....) t внутреннее соединение somthingTable. Где внутренний запрос возвращает большое количество результатов.
прочие советы 1. Выполнение чтения с подсказкой выполнения with (nolock), это грязно, и я не рекомендую его, но он будет иметь тенденцию быть быстрее. 2. Также посмотрите на план выполнения sql, который вы пытаетесь запустить и уменьшить сканирование строк, порядок, в котором вы соединяете таблицы. 3. посмотрите на добавление некоторых индексов в таблицы для более быстрого чтения. 4. Я также обнаружил, что удаление строк очень дорого, вы можете попытаться ограничить количество строк за вызов. 5. Переменные Swap @table с временными таблицами #также работали для меня в прошлом. 6. Возможно, вы также сохранили плохой план выполнения (слышал, никогда не видел).
надеюсь, что это помогает
Update: похоже, что запрос не выбросить любой тайм-аут. Соединение время вышло.
и. о. Вт., даже если вы не выполняете запрос, истекло время ожидания подключения? потому что есть два тайм-аута: connection и query. Все, кажется, сосредоточены на запросе, но если вы получаете тайм-ауты соединения, это сетевая проблема и не имеет ничего общего с запросом: соединение сначала должно быть установлено, прежде чем запрос может быть запущен, очевидно.
просто установите для свойства CommandTimeout sqlcommand значение 0, это заставит команду ждать завершения запроса... например:
SqlCommand cmd = new SqlCommand(spName,conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;