Правильный способ объявления курсора для огромного количества обновлений

StackOverflow https://stackoverflow.com/questions/2307779

  •  22-09-2019
  •  | 
  •  

Вопрос

Мне нужно несколько советов относительно того, хороша ли моя идея или нет.У меня есть ситуация, когда:

Мне нужно обновить каждую строку таблицы.В обновлении есть некоторая логика.Логика очень простая, но это нужно делать для каждой строки.Существует возможность обновления каждой строки.

В настоящее время я думаю о написании программы ESQL/C для этого.Я думаю о загрузке каждой строки в его эквивалентную структуру C через курсор Select For Update, запустите логику и совершает коммит.Какую роль играет ключевое слово HOLD для курсора?Я немного смущен этой ролью.

Эти обновления будут выполняться во время простоя системы.Таблица содержит около 130 миллионов строк.У него около 45 столбцов.Большинство столбцов имеют типы SMALLINT и INTEGER.

Я на правильном пути?Предложения приветствуются.

База данных будет Informix (IDS версии 11.50 FC6).

Это было полезно?

Решение

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

UPDATE YourTable
   SET y = (CASE WHEN z > x THEN p ELSE y)
 WHERE key_column BETWEEN lo_val AND hi_val;

Сложная часть, вероятно, будет заключаться в разделении работы на управляемые субтранзакции;вот что такое 'lo_val ..hi_val' состояние примерно.Если ваши логические журналы достаточно велики, чтобы обрабатывать все 130 миллионов обновляемых строк [около (2 * (размер строки + X) * количество строк), где X — это значение около 20, я полагаю] с запасом места, тогда вы можно сделать все сразу.Очевидно, что это «обновляет» каждую строку.

Если вы решили, что это необходимо сделать в клиенте (ошибка, но...), то:

Вы используете курсор SELECT с HOLD, чтобы он оставался открытым и правильно позиционировался во время транзакций.Вы запускаете транзакцию, получаете несколько тысяч строк, обновляя каждую по мере необходимости.Убедитесь, что вы используете подготовленный оператор UPDATE;возможно, вы используете условие WHERE CURRENT OF.


Предлагаете ли вы поместить обновление как часть курсора в хранимой процедуре?

Нет, хотя вы можете сделать это в хранимой процедуре.Частично это зависит от того, собираетесь ли вы делать это регулярно;если да, то, возможно, хранимая процедура — хорошая идея, но я бы не стал делать одноразовое упражнение.

Это зависит от того, как вы собираетесь определять lo_val и hi_val.Я бы, вероятно, использовал I4GL (потому что я свободно им владею), а затем ожидаю подготовить оператор UPDATE (с вопросительными знаками вместо «lo_val» и «hi_val»), а затем ожидаю выполнить это несколько раз, каждый раз образуя одну операторную транзакцию.Итак, если вы решили использовать диапазон lo_val..hi_val от 000000..099999, 100000..199999, ...тогда вы бы повторили:

for i = 0 to 10000000 step 100000
    let j = i + 99999
    execute p_update using i, j
end for

В I4GL вам не обязательно использовать подготовленный оператор.Если у вас есть IDS 11, вы можете подготовить отчетность в SPL.В более ранних версиях и без особого снижения производительности (сомневаюсь, что вы могли бы ее надежно измерить) вы могли бы просто использовать:

CREATE PROCEDURE update_your_table()
    DEFINE lo_val, hi_val INTEGER;

    FOR lo_val = 0 TO 1000000 STEP 100000
        LET hi_val = lo_val + 99999;
        UPDATE YourTable
           SET y = (CASE WHEN z > x THEN p ELSE y)
         WHERE key_column BETWEEN lo_val AND hi_val;
    END FOR;

END PROCEDURE;

Непроверенный код — используйте на свой страх и риск!

Другие советы

SPL - это путь!..но я предлагаю вам сначала скопировать таблицу и протестировать массовое обновление.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top