2016-05-05 3 views
1

Я не могу придумать способ ускорить это. Это делает сканирование таблицы, но я вроде как должен, потому что мне нужно обновить ВСЕ записи ...есть ЛЮБОЙ способ улучшить производительность по этому простому запросу?

Проблема в том, что эта таблица имеет МИЛЛИОНЫ записей ... примерно около 30 миллионов.

Это займет около 50 минут. У кого-нибудь есть подсказки о том, как я могу это улучшить?

update A 
    set  A.product_dollar_amt = round(A.product_dollar_amt, 2), 
      A.product_local_amt = round(A.product_local_amt, 2), 
      A.product_trans_amt = round(A.product_trans_amt, 2) 
    from dbo.table A 

В таблице в настоящее время куча (без кластерного индекса), так как он нигде не используется ... не уверен, что создание кластерного индекса позволит улучшить что-либо здесь.

+0

Как насчет обновления в партии? –

+0

как все будет иначе? –

+0

Вы можете отслеживать запрос с помощью sp_WhoIsActive и посмотреть, происходят ли какие-либо необычные ожидания. Вы также можете загрузить этот результат в таблицу _different_, а затем переименовать его (или переместить его в другую схему.Тогда изменение будет мгновенным, но вам нужно будет хранить две таблицы, полные ваших 30 миллионов записей. –

ответ

2

У вас действительно нет альтернатив здесь. Вы обновляете каждую строку, и это займет столько времени, сколько потребуется. Я могу сказать вам, что обновление 30M строк в одной транзакции не является отличной идеей. Вы можете легко взорвать свой журнал транзакций. И если эта таблица используется другими пользователями, вы, вероятно, собираетесь их блокировать до тех пор, пока вся таблица не будет обновлена. Вы намного лучше обновляете эту таблицу небольшими партиями. Общая производительность не будет улучшена, но вы столкнетесь с гораздо меньшим напряжением для вашего журнала и других пользователей.

3

Вот три варианта.

Первое упоминание Рэнди заключается в том, чтобы делать работу партиями.

Второй способ сбросить результаты во временную таблицу и воссоздать исходную таблицу:

select . . . , 
     product_dollar_amt = round(A.product_dollar_amt, 2), 
     product_local_amt = round(A.product_local_amt, 2), 
     product_trans_amt = round(A.product_trans_amt, 2) 
into a_temp 
from a; 

drop a; 

sp_rename 'a_temp', 'a'; 

Примечание: Это не гарантированно будет быстрее, а потому, что вход вставки идет быстрее, чем лесосечных обновлений, то часто бывает. Кроме того, вам нужно будет перестроить индексы и триггеры.

Наконец, есть решение «без обновления»: создание производных значений вместо:

sp_rename 'A.product_dollar_amt', '_product_dollar_amount', 'COLUMN'; 
sp_rename 'A.product_local_amt', '_product_local_amt', 'COLUMN'; 
sp_rename 'A.product_trans_amt', '_product_trans_amt', 'COLUMN'; 

Затем добавьте столбцы обратно в формулах:

alter table A add product_dollar_amt as (round(product_dollar_amt, 2)); 
alter table A add product_local_amt = round(product_local_amt, 2); 
alter table A add product_trans_amt = round(product_trans_amt, 2); 
0
  1. распараллеливания обновление с помощью варианты или подсказки, которые позволят вашему запросу сделать это;
  2. Если недоступно, вы можете вручную разделить работу на отдельных сеансах обновления, выполняемых одновременно. Это потребует от вас возможности эффективно разделить работу, желательно с помощью разделов.
  3. Отключить все и все служебные данные: отключить или сбросить индексы, отключить ведение журнала транзакций, позволяя моментально восстановить время и т. Д. В вашем случае индексы не повредят, поскольку вы не обновляете индексированные столбцы или добавляете новые строки.

    Теоретически с 16-ядерной системой (x2 для гиперпотока, доступной по архитектуре процессора). Работа на 50 минут будет выполняться в 3 минуты, если у вас нет других узких мест (диск io).

Смежные вопросы