Исключение тайм-аута соединения для запроса, использующего ADO.Net

StackOverflow https://stackoverflow.com/questions/105642

  •  01-07-2019
  •  | 
  •  

Вопрос

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

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

Я не могу используйте любой из этих методов: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();
    }
}
Это было полезно?

Решение

Поскольку вы используете ExecuteNonQuery, который не возвращает никаких строк, вы можете попробовать этот подход, основанный на опросе.Он выполняет запрос в обычном режиме (без обратного вызова) но приложение будет ждать (внутри цикла 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 секунд, даже в больших базах данных, если они правильно настроены.Если у вас есть веские доказательства, используя план запроса, что запрос не может быть выполнен быстрее, чем это, тогда вам следует увеличить время ожидания, другого способа сохранить соединение нет, это назначение времени ожидания - прервать соединение, если запрос не завершится в указанный промежуток времени.

Я должен согласиться с Черепахой.

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

Если это не вариант, или если вы хотите сначала попробовать что-то другое, вот ваши три основных варианта:

  1. Разбейте запрос на компоненты, которые выполняются по таймауту.Это, наверное, самое простое.
  2. Измените запрос, чтобы оптимизировать путь доступа через базу данных (обычно:набирайте индекс как можно ближе)
  3. Измените или добавьте индексы, чтобы повлиять на путь доступа к вашему запросу.

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

  1. Подтвердите с помощью вашего администратора базы данных и другой проверки кода, что вы действительно оптимизировали запрос как можно лучше
  2. Поработайте над базовой структурой БД, чтобы увидеть, есть ли какой-либо выигрыш, который вы можете получить на стороне БД, создавая / модифицируя idex (ы).
  3. Разделите его на несколько частей, даже если это означает запуск процедур с несколькими возвращаемыми параметрами, которые просто вызывают другой параметр.(Этот вариант не является элегантным, и, честно говоря, если ваш код ДЕЙСТВИТЕЛЬНО займет так много времени, я бы обратился к руководству и повторно обсудил 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.т. е.выберите * из (select ....) t внутреннего соединения с какой-либо таблицей.Где внутренний запрос возвращал очень большое количество результатов.

Другие советы 1.Выполнение операций чтения с помощью подсказки выполнения with (nolock), это грязно, и я не рекомендую это делать, но, как правило, это будет быстрее.2.Также посмотрите на план выполнения sql, который вы пытаетесь запустить, и уменьшите сканирование строк, порядок, в котором вы объединяете таблицы.3.посмотрите на добавление некоторых индексов в ваши таблицы для более быстрого чтения.4.Я также обнаружил, что удаление строк обходится очень дорого, вы могли бы попробовать ограничить количество строк на вызов.5.Замена переменных @table на #temporary tables также работала у меня в прошлом.6.Возможно, вы также сохранили плохой план выполнения (слышали, никогда не видели).

Надеюсь, это поможет

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

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

Возможно, стоит попробовать перелистать результаты обратно.

просто установите для свойства CommandTimeout sqlcommand значение 0, это заставит команду ждать завершения запроса...например:

SqlCommand cmd = new SqlCommand(spName,conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top