Как правильно обновлять большие таблицы, не делая большой переходный журнал? - PullRequest
0 голосов
/ 25 мая 2018

У меня есть имена таблиц tb_big размером 50 Гб.Если создать дополнительный столбец:

alter TABLE UAT_DM.ai_SUBS_MONTH_CLR ADD segment CHAR(5) not casespecific;

Все работает нормально.Все значения равны нулю, поэтому обновление будет работать довольно быстро (1+ минуты):

update tb_big
set segment = case when LT_month <= 4 then '0'
     when LT_month <= 8 then '1'
     when LT_month <= 12 then '2'
     when LT_month <= 17 then '3'
     when LT_month <= 24 then '4'
     when LT_month <= 36 then '5'
     when LT_month <= 56 then '6'
     when LT_month <= 83 then '7'
     when LT_month <= 96 then '8'
     else  '9' end;

Итак, допустим, я хочу обновить его во второй раз в том же столбце:

update tb_big
    set segment = case when LT_month <= 4 then '0'
         when LT_month <= 8 then '1'
         when LT_month <= 12 then '2'
         when LT_month <= 17 then '3'
         when LT_month <= 27 then '42'
         when LT_month <= 36 then '52'
         when LT_month <= 56 then '6'
         when LT_month <= 83 then '7'
         when LT_month <= 96 then '08'
         else  '9' end;

Из-за большихРазмер таблицы и некоторое неожиданное поведение TD, такое обновление будет работать при транзакции, поэтому каждое обновление будет записываться в временный журнал, который по неизвестной для меня причине будет сильно искажен (+ 99,9%) и займет терабайты буфера.Я почти поставил производственный сервер на колени (администратор TD не закрыл его и предпочел, чтобы он завершил работу и не смог выполнить резервное копирование, потому что откат назад может занять много времени. Это правда?)

Мой вопроскак правильно обновлять большие таблицы?Моя идея - отбросить этот столбец и повторить с самого начала.Однако я боюсь, что больше не получу сообщение об ошибке ( см. ).Хорошим возможным решением может быть создание новой пустой таблицы и копирование из первой таблицы со всеми столбцами, кроме той, которую нужно изменить.Но использование пространства x2 не является хорошей практикой.

Рекомендации администраторов TD не обновляют больше, чем 200 тыс. Строк, звучит для меня нелепо.

DDL таблицы, в которой 500 млн строк, размер 50 Гб:

CREATE MULTISET TABLE UAT_DM.ai_SUBS_MONTH_CLR ,NO FALLBACK ,
     NO BEFORE JOURNAL,
     NO AFTER JOURNAL,
     CHECKSUM = DEFAULT,
     DEFAULT MERGEBLOCKRATIO
     (
      CUST_ID DECIMAL(12,0),
      LT_month DECIMAL(15,2),
      days_to_LF(15,0),
      REV_COM DECIMAL(18,6),
      device_type VARCHAR(50) CHARACTER SET UNICODE CASESPECIFIC,
      usg_qq DECIMAL(18,0),
      usg_dd DECIMAL(18,6),
      report_mnth CHAR(7) CHARACTER SET UNICODE NOT CASESPECIFIC,
      MACN_ID DECIMAL(15,0),
      segment CHAR(5) CHARACTER SET LATIN NOT CASESPECIFIC)
UNIQUE PRIMARY INDEX ( SUBS_ID ,report_mnth )
INDEX ( CUST_ID )
INDEX ( segment );

1 Ответ

0 голосов
/ 28 мая 2018

Вы не сообщили очень важную деталь.

Сначала вы добавили новый столбец segment, а затем обновили его.

Затем вы создали вторичный индекс на segment.

Затем вы запускаете 2-е обновление.

Этот NUSI довольно мал из-за малого количества различных значений.Обслуживание также довольно дорого из-за большого количества повторяющихся значений (я никогда не проверял его, но это также должно быть причиной искаженного журнала переходных процессов).

Существует практическое правило (и оно похоже набольшинство (все?) СУБД): Не обновлять большой процент строк, когда это индексированный столбец.

Обычно вы делаете это один раз, а затем получаете вызов от администратора БД.никогда не забудет :-) (конечно, это не должно быть , вам лучше обновить траншами )

Удалите индекс перед обновлением, а затем заново создайте его.

Но почему вы помещаете вторичный индекс на segment?Вероятно, он не будет использоваться оптимизатором из-за его низкой селективности.Конечно, тогда вы можете сделать CASE в качестве вычисления вместо столбца.

И, предполагая, что SUBS_ID совпадает с CUST_ID, вы можете избавиться от 2-го NUSI, изменив Первичный индекс на PRIMARY INDEX ( SUBS_ID ), вероятно, не слишком много строк на SUBS_ID.Если вы получаете доступ к лоту с помощью report_mnth, вы можете разделить его (тогда вам лучше изменить его на INT, 201805 вместо '2018-05').

...