Правильный способ объявления курсора для огромного количества обновлений - PullRequest
1 голос
/ 22 февраля 2010

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

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

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

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

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

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

Ответы [ 2 ]

2 голосов
/ 22 февраля 2010

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

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;

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

0 голосов
/ 28 февраля 2010

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

...