Как мне уменьшить стоимость set_bit в Postgres? - PullRequest
0 голосов
/ 22 сентября 2018

Я использую PostgreSQL 9.6 и провожу эксперимент со следующей структурой таблицы:

CREATE TABLE my_bit_varying_test (
  id SERIAL PRIMARY KEY,
  mr_bit_varying BIT VARYING
);

Чтобы понять, какой производительности можно ожидать, если я одновременно сбрасываю биты на 100 000-битных данных, янаписал небольшой блок PL / pgSQL следующим образом:

DO $$
DECLARE
  t  BIT VARYING(100000) := B'0';
  idd INT;
BEGIN
  FOR I IN 1..100000
  LOOP
    IF I % 2 = 0 THEN
      t := t || B'1';
    ELSE
      t := t || B'0';
    end if;
  END LOOP ;

  INSERT INTO my_bit_varying_test (mr_bit_varying) VALUES (t) RETURNING id INTO idd;
  UPDATE my_bit_varying_test SET mr_bit_varying = set_bit(mr_bit_varying, 100, 1) WHERE id = idd;
  UPDATE my_bit_varying_test SET mr_bit_varying = set_bit(mr_bit_varying, 99, 1) WHERE id = idd;
  UPDATE my_bit_varying_test SET mr_bit_varying = set_bit(mr_bit_varying, 34587, 1) WHERE id = idd;
  UPDATE my_bit_varying_test SET mr_bit_varying = set_bit(mr_bit_varying, 1, 1) WHERE id = idd;

  FOR I IN 1..100000
  LOOP
    IF I % 2 = 0 THEN
      UPDATE my_bit_varying_test
      SET mr_bit_varying = set_bit(mr_bit_varying, I, 1)
      WHERE id = idd;
    ELSE
      UPDATE my_bit_varying_test
      SET mr_bit_varying = set_bit(mr_bit_varying, I, 0)
      WHERE id = idd;
    end if;
  END LOOP ;
END
$$;

Когда я запускаю PL / pgSQL, это занимает несколько минут, и я сузил его до цикла for, который обновляетТаблица.Работает ли он медленно из-за сжатия в столбце BIT VARYING?Есть ли способ улучшить производительность?

Редактировать Это моделируемый, упрощенный пример.На самом деле это то, что у меня запущены десятки тысяч заданий, каждое из которых должно сообщать о своем состоянии, которое обновляется каждые несколько секунд.

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

Так, например, у вас может быть 5 рабочих на одну работу.Если они все выполнены, то статус будет «01111», что означает, что все задания выполнены, и ни одно из них не удалось.Если рабочий номер 2 дает сбой, то отображается состояние «111110», указывающее, что произошла ошибка, и все рабочие завершили, кроме последнего.

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

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Если ваша проблема заключается в сжатии TOAST, вы можете просто отключить его для этой таблицы:

ALTER TABLE my_bit_varying_test SET STORAGE EXTERNAL;
0 голосов
/ 24 сентября 2018

Вы можете попробовать подход, основанный на множестве, чтобы заменить второй цикл.Подход, основанный на множестве, обычно более толстый, чем циклическийИспользуйте generate_series() для получения индексов.

UPDATE my_bit_varying_test
       SET mr_bit_varying = set_bit(mr_bit_varying, gs.i, abs(gs.i % 2 - 1))
       FROM generate_series(1, 100000) gs(i)
       WHERE id = idd;

Также рассмотрите возможность создания индекса на my_bit_varying_test (id), если у вас его еще нет.

...