Как отправлять тысячи SQL-запросов асинхронно - PullRequest
1 голос
/ 27 июля 2010

Мы пишем простое приложение:

  • построить тысячи операторов выбора SQL
  • запустить каждый выбор с помощью BeginExecuteReader
  • поместить результаты в другую базу данных

Мы попробовали несколько вещей, которые либо оставляют соединения в состоянии SUSPENDED (как проверено sp_who2), либо занимают намного больше времени, чем просто сам запрос SQL (возможно, какая-то взаимоблокировка?).

Мы:

  • вызов EndExecuteReader в обработчике обратного вызова.
  • вызов conn.Close () и conn.Dispose ()
  • рекурсивный запуск другого вызова

public static void StartQuery() {
  // build the query for array[i]
  // ...
  SqlConnection conn = new SqlConnection(AsyncConnectionString);
  conn.Open();
  cmd.BeginExecuteReader(CallbackHandler, cmd);

  i++;
}



public static void CallbackHandler(IAsyncResult ar) {
     // unpack the cmd
     cmd.EndExecuteReader();

     // read some stuff to a DataTable...

     // SqlBulkCopy to another database (synchronously)

     cmd.Connection.Close();
     cmd.Connection.Dispose();

     StartQuery();
 }

Есть ли у кого-нибудь рекомендации или ссылки на надежный шаблон для решения проблемы такого типа?

Спасибо!

1 Ответ

4 голосов
/ 27 июля 2010

Полагаю, вы установили AsyncronousProcessing в строке подключения.Тысячи запросов BeginExecute, объединенных в CLR, - это путь к катастрофе:

  • вы будете быстро ограничены max worker threads в SQL Server и начнете испытывать длительное соединение Open время и частые тайм-ауты.
  • при параллельной работе 1000 нагрузок гарантированно будет намного медленнее, чем при последовательной работе 1000 нагрузок по N соединениям, где N определяется числом ядер на сервере.Тысячи параллельных запросов просто создадут чрезмерную конкуренцию на общих ресурсах и замедлят друг друга.
  • У вас нет абсолютно никакой надежности с тысячами запросов, поставленных в очередь в CLR.Если процесс завершается сбоем, вы теряете всю работу без какой-либо трассировки .

Гораздо лучший подход состоит в том, чтобы использовать очередь, из которой пул рабочих исключает нагрузки, и выполнять их.Типичный производитель-потребитель.Количество рабочих (потребителей) будет настроено ресурсами SQL Server (ядра ЦП, память, схема ввода-вывода нагрузок), но безопасное число в 2 раза больше количества ядер сервера.Каждый работник использует выделенное соединение для своей работы.роль рабочих и роль очереди не в том, чтобы ускорить работу, а наоборот, они действуют как механизм throttling , предотвращающий перегрузку сервера.

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

И, наконец, вы можете просто позволить SQL Server обрабатывать все: очереди,регулирование и сама обработка с помощью Activation .См. Асинхронное выполнение процедуры и следующую статью Передача параметров в фоновую процедуру .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...