#c# #tsql #loops
#c# #tsql #циклы
Вопрос:
Какой был бы наиболее эффективный способ перебрать 25 000 записей и, основываясь на некоторой заранее написанной логике vb, которая никогда не изменится (уверен на 99%), обновить столбец результатов в таблице до значения 1, 2 или 3?
Производительность и надежность здесь наиболее важны. Это, скорее всего, будет вызываться через клиент-серверное приложение в сети, но было бы неплохо иметь возможность вызывать его из веб-приложения. Я думаю о 3 разных способах сделать это с помощью T-SQL, C #.
a. Напишите объект, который выполняет хранимую процедуру, получает 25 000 записей, используйте коллекцию foreach для просмотра каждой записи и, основываясь на некоторой логике c #, вызывайте объект в каждой записи, которая выполняет хранимую процедуру, для обновления этой строки. Это привело бы к вызову объекта 25 000 раз (и процедура, я предполагаю, просто повторно использовала бы план выполнения)
или
b. Напишите хранимую процедуру, которая получает 25 000 записей, используйте запрещенный курсор для просмотра каждой записи и, основываясь на некоторой логике T-SQL, обновите эту строку в этой хранимой процедуре.
или
ОБНОВЛЕНО: МОЕ РЕШЕНИЕ ЗАКЛЮЧАЕТСЯ В СЛЕДУЮЩЕМ, чего бы это ни стоило, я использую сохраненные вычисляемые столбцы и разбиваю цикл на более мелкие инструкции update для обновления столбца (все завернуто в транзакцию). Смотрите статью ниже. Я думаю, что это будет действительно быстро, по сравнению с циклом..
Комментарии:
1. Какой код необходимо запускать над каждой строкой? Возможно, мы сможем полностью отказаться от итеративного подхода.
Ответ №1:
Очевидно, у вас есть какое-то условие, которое определяет, должно ли значение быть 1,2 или 3. Вы могли бы просто выполнить 3 запроса на обновление. Каждый запрос обновлял бы записи на основе условия, которое определяет, должно ли значение быть 1, 2 или 3. Не загружайте все данные на свой компьютер, если это в ваших силах.
Комментарии:
1. это плюс триггер для автоматического вычисления в каждой строке, чтобы вам никогда не приходилось делать это снова.
Ответ №2:
Моим первым выбором было бы сделать все это на SQL, если бы я мог, т. Е. обновить xxx set col = 1 где (ваша логика здесь), обновить xxx set col = 2 где (логика) и т.д.
Если вам нужно выполнить логику в клиенте vb, либо в веб-приложении, либо на клиентском сервере, моим выбором было бы использовать datareader для прохождения по записям (извлекая только требуемые столбцы, а не всю строку) и либо выполнить обновление TSQL, либо хранимую процедуру для вызова обновления тех записей, которые необходимо обновить, по одной за раз).
datareader обеспечит вам наилучшую производительность; SP должен работать по крайней мере так же хорошо, если не лучше, чем обновление TSQL, (но, вероятно, ненамного).
РЕДАКТИРОВАТЬ: Избегайте курсоров на стороне сервера (почти) любой ценой…они настоящие свиньи.
Ответ №3:
Решение этой проблемы без ввода c # на самом деле является лучшим вариантом, если ключевым является производительность. Выполняйте свои запросы вне c #. Если это действительно необходимо, используйте DataReaders.
Ответ №4:
Я бы не выбрал вариант B. По моему опыту, использование курсоров происходит чрезвычайно медленно.
C. Используйте DataReader и обновляйте записи с помощью ExecuteNonQuery
Ответ №5:
Как насчет опции (C) Хранимой процедуры, которая обновляет таблицу, используя логику на основе наборов, а не курсор:
...
update x set col = f(x)
from x
...
Комментарии:
1. Мне кажется, что вызов сохраненной процедуры и циклический просмотр каждой записи будет быстрее, чем запись обработки на клиенте и необходимость каждый раз переходить от клиента к серверу БД для обновления записи. Да / Нет??
2. Зачем вам «перебирать каждую запись» в SQL. SQL — это все о наборах и обработке на основе наборов. Инструкция update обновляет 0, 1 или 500 000 строк или сколько бы ни возвращало ее предложение where. Вы выполняете хранимую процедуру. Он выполняет свою работу и не возвращается, пока не будет выполнен. Обновление 25 000 строк на правильно настроенном SQL Server не должно даже заставить SQL Server тяжело дышать, не говоря уже о том, чтобы вспотеть.
3. Совершенно верно.. Я написал исходный код 12 лет назад, когда был новичком, и с тех пор многому научился.. В итоге мы получили сохраненные вычисляемые столбцы и предложение ol where и несколько разных запросов, обернутых в транзакцию..
Ответ №6:
В зависимости от того, как работают обновления, у вас есть пара вариантов.
-
Создайте вычисляемый столбец, в котором сохраняются результаты. Таким образом, при изменении записи она будет обновляться в одном месте.
-
Вместо выполнения 25 000 запросов на обновление просто используйте sqlbulk load.
-
(и это мое предпочтение). Попросите ваше приложение отправить параметры на SQL Server для того, что нужно обновить. В этом случае я бы предпочел использовать статический курсор, поскольку это было бы немного быстрее, если бы одна запись не обязательно влияла на следующую.
Ответ №7:
Вы можете либо:
-
Используйте 3 отдельных обновления, предложенных @Andrew
-
Извлеките записи во временную таблицу и просматривайте их партиями по 1000 записей за раз в цикле WHILE для инструкции UPDATE (таким образом, 25 циклов / обновлений)
-
Или, если вы используете SQL Server 2008 (или новее) и алгоритм определения изменения сложный, вы можете собрать 25 000 строк в коллекцию на .Сетевая сторона и потоковая передача изменений обратно в Proc, который имеет табличный параметр и выполняет одно обновление. Вы можете найти пример этого на:
http://www.sqlservercentral.com/articles/SQL Server 2008/66554/
В каждом случае вы хотите избежать 25 000 вызовов ОБНОВЛЕНИЯ.
Ответ №8:
У меня похожая ситуация. На самом деле, у меня > 10.000.000 записей. Бизнес-логика была довольно сложной, и существовал старый код, написанный исключительно на SQL. Менеджеры сказали мне, что со старым кодом на 1 000 000 записей уходит более 15 часов. С моим решением мне потребовалось буквально всего 5 минут! Я сделал это в цикле, который состоит из 3 шагов в итерации, и каждая итерация занимала одну партию записей:
- Массовая загрузка счетов. Я не помню размер пакета, я думаю, что это было около нескольких тысяч.
- Выполнение бизнес-логики для загруженных записей
- Массовая вставка. Поскольку это было массово, это не могло быть обновлением. Таким образом, это было скопировано во временную таблицу с почти такой же структурой, что и исходная таблица, а затем обновлено по ключу в исходной таблице. Временная таблица опустошалась / удалялась при каждой массовой вставке. Это намного быстрее, чем стандартное обновление.