Как распараллелить запрос базы данных с помощью ThreadPool?
Я исправляю ошибки в чужом коде, где требуется целая вечность, чтобы вернуть полный набор данных в следующем коде:
DataTable dt = someLib.GetDataTable("EXEC [dbo].[CMS_Content_GetAllContents]");
// Copy the DataTable data to list.
foreach (DataRow dr in dt.Rows)
{
ContentInfo aContentDetail = new ContentInfo(
(int)dr["ID"],
(string)dr["ContentName"],
getCategories((int)dr["ID"]),
null,
(string)dr["Publisher"],
(string)dr["Price"],
false);
contentInfoList.Add(aContentDetail); ;
}
private string getCategories(int ContentID)
{
String categories = String.Empty;
String query = String.Format("EXEC [dbo].[CMS_Content_GetContentCategories] @ID = {0}", ContentID);
DataTable dt = clsGlobal.GetDataTable(query);
foreach (DataRow dr in dt.Rows)
{
categories = String.Concat((string)dr["ShortDescription"] + ", ");
}
if (categories.EndsWith(", "))
categories = categories.TrimEnd(new char[] { ',', ' ' });
return categories;
}
Это жалко, так как существует более 1000 строк для DataTable dt, и я не могу иметь дело с ним с уровня хранимых процедур!
Мне просто интересно, могу ли я связать вызов getCategories(int)
в Threadpool.QueueUserWorkItem()
таким образом, что он может идти параллельно, но не знаю, как вернуть строку обратно вызывающему?
Или, это плохая идея использовать Threadpool, потому что я слышал, что Рабочие потоки Threadpool не предназначены для длительных запросов, таких как вызовы DB, поскольку поток портов IOCompletion может не вернуться вовремя, поэтому рабочие потоки, вероятно, будут заблокированы из-за этого?
Любая помощь ценится.
2 ответа:
Боюсь, что в данном случае (вкл или выкл threadpool) потоковая обработка не является ответом. Фиксация 1000 вызовов к базе данных есть. Вы можете оптимизировать скорость вашего ответа для небольшого числа пользователей, но время ответа все равно будет довольно мучительным, и ваше приложение будет падать при очень низкой нагрузке.
Я не знаю, насколько сильно вы контролируете базу данных, поэтому вот несколько идей, которые охватывают несколько слоев:
- вытяните категории с содержимым. Вы можете либо создать функцию func для их разграничения по строкам, либо использовать proc, который возвращает несколько наборов данных в одном вызове.
- Загрузите все категории сразу и поместите данные вместе в память
- измените свой пользовательский интерфейс так, чтобы вы не использовали 1000 элементов CMS сразу. Пейджинг или что-то в этом роде.
Удачи.
Хотя, вопрос был ответом. Но это только для того, чтобы помочь.
Вы можете "переместить" свой код в рабочий поток и позволить ему работать. Вы также можете создать добавить событие, и как только поток завершит работу, он даст вам знать. Таким образом, вы можете продолжить (или переместить индикатор прогресса до конца, если у вас есть?) с остальной вашей работой.
- Здесь - это то, как вы работаете с потоками.
- это то, что я люблю, на сегодняшний день.
В качестве примечания я считаю, что это можно сделать в SP (если вы можете поделиться запросом); поэтому я бы создал SP, который извлекает детали контента, и для каждого ContentDetailID я бы подготовил разделенный запятыми список категорий, а затем вернулся бы с моим результатом.
Итак, ваш вызов будет просто:
DataTable dt = someLib.GetDataTable("EXEC [dbo].[CMS_Content_GetAllContents_Ex]");//Note the _EX in the sp name (0: