Как распараллелить запрос базы данных с помощью 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 2

2 ответа:

Боюсь, что в данном случае (вкл или выкл threadpool) потоковая обработка не является ответом. Фиксация 1000 вызовов к базе данных есть. Вы можете оптимизировать скорость вашего ответа для небольшого числа пользователей, но время ответа все равно будет довольно мучительным, и ваше приложение будет падать при очень низкой нагрузке.

Я не знаю, насколько сильно вы контролируете базу данных, поэтому вот несколько идей, которые охватывают несколько слоев:

  1. вытяните категории с содержимым. Вы можете либо создать функцию func для их разграничения по строкам, либо использовать proc, который возвращает несколько наборов данных в одном вызове.
  2. Загрузите все категории сразу и поместите данные вместе в память
  3. измените свой пользовательский интерфейс так, чтобы вы не использовали 1000 элементов CMS сразу. Пейджинг или что-то в этом роде.

Удачи.

Хотя, вопрос был ответом. Но это только для того, чтобы помочь.

Вы можете "переместить" свой код в рабочий поток и позволить ему работать. Вы также можете создать добавить событие, и как только поток завершит работу, он даст вам знать. Таким образом, вы можете продолжить (или переместить индикатор прогресса до конца, если у вас есть?) с остальной вашей работой.

  1. Здесь - это то, как вы работаете с потоками.
  2. это то, что я люблю, на сегодняшний день.

В качестве примечания я считаю, что это можно сделать в SP (если вы можете поделиться запросом); поэтому я бы создал SP, который извлекает детали контента, и для каждого ContentDetailID я бы подготовил разделенный запятыми список категорий, а затем вернулся бы с моим результатом.

Итак, ваш вызов будет просто:

DataTable dt = someLib.GetDataTable("EXEC [dbo].[CMS_Content_GetAllContents_Ex]");//Note the _EX in the sp name (0: