Коммит миграций кусками с помощью psql

Я ещё не так давно работаю с «Постгресом» и раз в месяц натыкаюсь на что-то неожиданное.

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

В «Оракле» такую миграцию наши ребята, насколько я знаю, разбивали хранимой процедурой на части и коммитили внутри кусками по миллиону, в «Постгресе» так нельзя — блок на языке PL/pgSQL выполняется в собственной транзакции и она прервётся при попытке сделать COMMIT. Автономных транзакций нет.

Испытания на тестовом стенде, приближенном к промышленному, показали, что единым куском обновить не получится — на мастере и слейве первой очереди кончилось место и стенд развалился. Надо было найти какой-то эквивалент сбросу миграции в цикле, по типу того как это делается в «Оракле».

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

DO $$
  DECLARE
    max_id table.id % TYPE;
    query TEXT;
BEGIN
  -- делим таблицу на куски по миллиону, теперь в max_id у нас номер последнего куска
  SELECT CEIL(MAX(id)::float/1000000) INTO max_id FROM mytable;

  -- очищаем файл /tmp/sqlquery
  COPY (SELECT '') TO '/tmp/sqlquery';

  -- айдишники в моём конкретном случае идут с единицы, но более правильно идти с минимума до максимума с шагом
  FOR i IN 0..max_id LOOP
        query = FORMAT(
            'UPDATE mytable '
            'SET something=value '
            'WHERE id BETWEEN ' || i*1000000+1 || ' AND ' || (i+1)*1000000 || ';'
        );

        -- запуск /bin/cat нужен, чтобы дописывать в файл
        EXECUTE  'COPY (SELECT ' || quote_literal(query) || ') TO PROGRAM ''/bin/cat >> /tmp/sqlquery''';
  END LOOP;
END$$;

-- запуск запроса
\i /tmp/sqlquery

Я воспользовался тем, что в накатке миграции у нас участвует утилита psql — официальный консольный клиент к «Постгресу», помимо команд СУБД она умеет выполнять свои собственные команды, чем я и пользуюсь — собираю нужные запросы в файл и запускаю его на выполнение в последней строке.

Обратите внимание на вызов /bin/cat — это важно, так как команда COPY сама не умеет добавлять что-то в файл, она его перезаписывает.

2 комментария

Оригинальный арифмометр Однера (X-9 S-5)

Если помните, то в прошлом году мы с группой товарищей основали «Музей вычислительной техники им. Р. К. Самитова», после открытия я взял паузу, кое-что переосмыслил и с новыми силами взялся за розыск экспонатов. Один из них доставили из Штатов сегодня.

Вильгодт Теофил Однер — шведско-русский механик, изобретатель, разработчик «Арифмометра Однера» — который в 1940-е стал самым популярным механическим калькулятором в мире. В 1886 году он открыл небольшую мастерскую в Петербурге, которая в 1890-х произвела первый арифмометр. После смерти Вильгодта в 1905 году его компания перешла к его сыну Александру, который управлял ею вместе с партнёром отца — Френком Хиллом.

Original Odhner (77.27КиБ)
Арифмометр 1950-х годов, произведённый компанией «Оригинал Однер»

После революции компания ожидаемо была национализирована, что привело к её разделению — новоявленное государство производило свои арифмометры «Оригинал-Однер», Александр же с прочими управляющими открыл в Швеции собственное производство.

В последующие годы компания несколько раз меняла владельцев и даже название, пока в 1973 году её не купила «Электролюкс».

На фотографии выше — «Original Odhner X-9 S-5», произведённый в Швеции в 1950-х годах. «Икс» означает, что модель оснащена мотором, «Эс» — с прямым вычитанием (что бы это ни значило), «5» — номер серии, «9» — номер модели в серии.

Несмотря на то, что этот арифмометр имеет опосредованное отношение к России, я всё же приобрёл её для музея, так как Вильгодта Однера сегодня никто, кроме специалистов, не знает и об его арифмометре — тоже. Это скверно, хочется это исправить.

Пересылка, к слову, стоила в несколько раз больше самой посылки — сказался вес почти в 13 килограмм.

Продавец утверждает, что модель рабочая, но проверить это не могу — дома нет нужного напряжения, да и не рискнул бы всё равно — нужно разбирать в нормальных условиях и хотя бы визульно убедиться, что всё в порядке перед включением. Поэтому как именно устройство работает рассказать не могу. Знатоков немецкого отсылаю к инструкции.

2 комментария