Прочитайте 5 миллионов записей и, наконец, обновите столбец - PullRequest
3 голосов
/ 24 августа 2011

Мне нужно обновить 5 миллионов + записей в базе данных для таблицы T1.Это C# tool, который будет READ (Select) столбцом в таблице T1, скажем, T1.col1, затем извлечет значение на основе логики из этого столбца и, наконец, UPDATE другой столбец T1.col2 в том жетаблицы с этим обработанным значением и обновлением базы данных.

Требуются некоторые мнения о наилучшем / оптимизированном способе достижения этого в C # / ADO.NET?

ПРИМЕЧАНИЕ. Логика извлечения не можетбыть частью SQL.Эта логика встроена в COM DLL, которую я извлекаю из .NET и применяю к значению столбца Col1, чтобы сгенерировать новое значение, которое должно быть окончательно сохранено в T1.Col2.

Ответы [ 7 ]

1 голос
/ 24 августа 2011

Поскольку вам нужно передать данные для какой-либо операции с помощью COM-объекта, я бы сделал следующее:

Использование машины с большим объемом памяти - загрузка данных в виде кусков (например, 5000 или 50000 строк одновременно) в память, обработка их и обновление на SQL Server ...

Для части UPDATE используйте транзакции и поместите 5000 - 20000 UPDATE в одну транзакцию ...

[РЕДАКТИРОВАТЬ] : правильно разделив работу и присвоив 500000 или 1000000 строк одной «рабочей машине», вы можете ускорить это до максимального ограничения вашего SQL Server ... [/ EDIT]

Другой вариант - хотя и не рекомендуется (только из-за теоретически возможных проблем безопасности и / или стабильности, представленных объектом COM в данном конкретном случае):

Хотя это описание SQL Server, подобное возможно и в Oracle на Windows

Вы можете поместить логику этого преобразования в свой SQL Server, написав + установив сборку .NET, которая предоставляет хранимую процедуру, которую можно вызвать для выполнения преобразования ... Сборка .NET, в свою очередь, обращается к этому COM-объекту. Как посмотреть http://www.sqlteam.com/article/writing-clr-stored-procedures-in-charp-introduction-to-charp-part-1

Ссылка MSDN на это http://msdn.microsoft.com/en-us/library/ms131094.aspx

0 голосов
/ 24 августа 2011

Если это разовая сделка, то выведите более 5 миллионов записей в файл.Запустите логику для файла, чтобы сгенерировать новые записи.Логика дампа и файла должна быть быстрой и не такой трудоемкой.Затем BULK вставляет обновленные данные в промежуточную таблицу.

В этот момент устаревшая таблица становится устаревшей и превращает промежуточную таблицу в настоящую таблицу с некоторыми операторами DDL для вставки в соответствующие индексы, FK и т. Д.

Это был бы самый быстрый способ справиться с таким количеством записей.Все остальное, и, вероятно, потребуется всего несколько дней, чтобы обработать все.

0 голосов
/ 24 августа 2011

Некоторые основные указатели:

  1. Используйте DataReader, а не DataSet.Переполнение памяти в DataSet, вероятно, создаст проблемы с таким количеством строк
  2. Если возможно, запустите вычислительную часть в нескольких потоках параллельно.Вы можете сделать это, используя для этого TPL , но поскольку вы используете COM-компонент, могут возникнуть некоторые проблемы с доступом к нему из нескольких потоков.Проконсультируйтесь с экспертом по COM (или откройте еще один вопрос SO) о том, как определить, является ли ваш COM-компонент потокобезопасным.
  3. Не оставляйте открытыми ни одну крупную транзакцию при вычислении результата.Используйте подсказку «with (nolock)», если это соответствует вашей семантике.Это поможет предотвратить воздействие ваших задач на других читателей / писателей.
0 голосов
/ 24 августа 2011

При выполнении этих операций вы хотите, чтобы пользователь дождался их окончания? Или вы можете запустить эту задачу в фоновом режиме? Может быть, даже ночью во время какой-то запланированной обработки? Если последнее верно, вы можете придерживаться своего подхода и просто выполнить все свои миллионы обновлений, просто убедитесь, что вы не заставляете пользователя ждать завершения операции. В противном случае вам действительно нужно продумать способ переноса всей логики обновления в базу данных.

Таким образом, в зависимости от требований, варианты будут:

1) Запустите отдельный поток (или даже несколько потоков) для выполнения обновлений, в то время как основной поток вернет пользователю что-то вроде «Длительная операция выполняется. Пожалуйста, вернитесь на эту страницу позже, чтобы увидеть ее состояние»

2) запускать обновления ночью в отдельном процессе

3) Реорганизовать проект так, чтобы вы могли позволить себе выполнять обновления в базе данных.

UPDATE

Я вижу, как вы постоянно говорите, что не можете перенести логику обновления в базу данных. Если вы не несете ответственности за архитектуру проекта, можете ли вы повлиять на управление, чтобы реорганизовать весь материал? Похоже, плохая архитектура, если такие операции необходимы.

0 голосов
/ 24 августа 2011

Вам действительно нужно обновить col2 новым значением?

Если каждая строка получает значение smmae, я записываю его в отдельную таблицу с 1 строкой и просто объединяю эту строку, когда вам нужно вернуть результат.

вот так:

update t2 
set col2 = 1234 -- the computed value over all rows in t1

select t1.col1, 
       t2.col2 
from   t1
       cross join t2 -- t2 only has 1 row

Обновления относительно дороги, и запись в 1 строку, безусловно, намного дешевле, чем запись в 5 миллионов.

Иначе я бы поставил мельницу там, где находится дерево, поэтому, если возможно, используйте TSQL.Опять же, 5 миллионов не такая уж большая проблема, можете ли вы обработать их на сервере или вам нужно перетаскивать их по сети?В последнем случае это действительно складывает.

Ргдс Герт-Ян

0 голосов
/ 24 августа 2011

Это много данных, которые должны быть в памяти одновременно.Я бы порекомендовал по возможности извлекать данные небольшими партиями записей из COM DLL и обрабатывать их.Использование PLinq для объектов позволит вам максимально использовать процессор.Между ними вы сможете найти счастливую среду, которая хорошо работает.

0 голосов
/ 24 августа 2011

На сегодняшний день самый быстрый способ - выполнить обновление в самом коде SQL:

UPDATE T1
SET col2 = [some function based on col1]

(Учтите, что в зависимости от платформы базы данных это может привести к разрыву журнала транзакций. В частности, для MS SQL я бы рекомендовал обновлять небольшими партиями, возможно, по 100 тыс. Строк или меньше)

Если логика функции слишком сложна для этого, убедитесь, что вы выпускаете все свои 5 миллионов обновлений на основе первичного ключа:

UPDATE T1
SET col2 = @newval
WHERE tableID = @id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...