如何减少Postgres中set_bit的成本?

时间:2018-09-22 18:46:55

标签: postgresql sql-update plpgsql

我正在运行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 :(得分:1)

您可以尝试使用基于集合的方法来替换第二个循环。基于集合的方法通常比循环更胖。使用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)上创建索引。

答案 1 :(得分:1)

如果确实是TOAST压缩是您的问题,则可以为该表禁用它:

ALTER TABLE my_bit_varying_test SET STORAGE EXTERNAL;