Исключение тайм-аута подключения для запроса с использованием ADO.Net - PullRequest
9 голосов
/ 20 сентября 2008

Обновление : похоже, что запрос не выбрасывает время ожидания. Время ожидания истекло.

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

Я не могу использовать любой из этих методов: 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 ]

16 голосов
/ 20 сентября 2008

Поскольку вы используете 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));
4 голосов
/ 20 сентября 2008

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

1 голос
/ 09 мая 2009

Это Гадкий взлом, но может помочь временно решить вашу проблему, пока вы не сможете решить реальную проблему

    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++;
            }
        }
    }
1 голос
/ 06 мая 2009

Если вам запрещено использовать функции API доступа к данным, чтобы запрос длился более 30 секунд, тогда нам нужно увидеть SQL.

Повышение производительности при оптимизации использования ADO.NET незначительно по сравнению с преимуществами оптимизации SQL.

И вы уже используете самый эффективный метод выполнения SQL. Другие методы были бы намного медленнее (хотя, если вы быстро извлекли свои строки и по-настоящему медленно работали на стороне клиента, используя DataSets, вы могли бы уменьшить начальный поиск до 30 секунд, но я сомневаюсь в этом. )

Если бы мы знали, что вы делаете вставки, то, возможно, вам следует использовать массовую вставку. Но мы не знаем содержание вашего sql.

1 голос
/ 20 сентября 2008

Недавно у нас была похожая проблема с базой данных 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 также содержит очень интересный монитор активности, который позволяет видеть состояние вашей базы данных во время запроса.

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

1 голос
/ 20 сентября 2008

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

  1. Подтвердите с вашими администраторами баз данных и другим обзором кода, что вы действительно оптимизировали запрос как можно лучше
  2. Поработайте над базовой структурой БД, чтобы увидеть, есть ли какой-либо выигрыш, который вы можете получить на стороне БД, создавая / изменяя idex.
  3. Разделите его на несколько частей, даже если это означает выполнение процедур с несколькими возвращаемыми параметрами, которые просто вызывают другой параметр. (Этот вариант не элегантен, и, честно говоря, если ваш код действительно займет много времени, я бы обратился к руководству и пересмотрел 30-секундный таймаут)
1 голос
/ 20 сентября 2008

Я должен согласиться с Террапином.

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

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

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

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

0 голосов
/ 12 мая 2009

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

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

0 голосов
/ 12 мая 2009

Вы пытались обернуть ваш sql внутри хранимой процедуры, они, кажется, имеют лучшее управление памятью. Мы видели подобные тайм-ауты раньше в планировании SQL-оператора с внутренними запросами с использованием классического ADO. то есть выберите * из (выберите ....) t внутреннего соединения somthingTable. Где внутренний запрос возвращал очень большое количество результатов.

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

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

...