sequential_uuid(UUID生成)

sequential_uuid插件可以生成两个具有顺序模式的UUID生成器,可以帮助您减少完全随机的UUID生成器所带来的随机I/O问题。

前提条件

支持的PolarDB PostgreSQL版的版本如下:

  • PostgreSQL 14(内核小版本14.5.1.0及以上)

  • PostgreSQL 11(内核小版本1.1.28及以上)

说明

您可通过如下语句查看PolarDB PostgreSQL版的内核小版本号:

  • PostgreSQL 14

    SELECT version();
  • PostgreSQL 11

    SHOW polar_version;

背景信息

常规的随机UUID生成器将在给定的范围内均匀取值,这意味着向索引插入数据时,其局部性较差,所有索引叶所在的页都有同样的概率被命中,从而导致整个索引会被强制放入内存中。当使用小索引不会存在这个问题,但一旦索引大小超过共享缓冲区(或者RAM)大小,缓存命中率就会迅速下降。

基于序列、时间戳的UUID与随机UUID相比,前者具有顺序模式,可以使新数据几乎总是在索引的最右侧插入(新的序列值大于所有先前的值,时间戳相同),从而有利于提升缓存命中率。

说明
  • 具有顺序模式的UUID生成器增加了UUID的可预测性,且增大了发生跨机冲突的概率。

  • 更多顺序UUID优势请参见Sequential UUID Generators

sequential_uuid的主要目标是生成更具顺序性的UUID生成器,且不会过多地降低随机性(随机性降低可能会增加碰撞的概率以及UUID的可预测性)。

生成器设计

使UUID更具顺序性最简单的方法是使用一些顺序值作为前缀。例如,可以采用序列或时间戳并添加随机数据,直到UUID的随机性达到16 B。这种方法得到的UUID几乎是完全连续的,但这种方法存在以下两个问题:

  • 随机性减少:如果使用了产生bigint值的序列,产生UUID的随机性将从16 B降低到8 B,时间戳也以类似的方式降低了随机性,具体取决于时间戳的精度。随机性的下降增加了碰撞概率和可预测性(比如,可以确定哪些UUID是彼此靠近生成的,甚至还可以推测出具体的时间戳)。

  • 膨胀:如果数值持续增长,可能会导致删除历史数据后索引膨胀,例如,日志表中对时间戳的索引。

为了解决这两个问题,sequential_uuid生成的UUID生成器被设计为定期回环,回环将发生在生成一定数量的UUID之后,或者在一段时间之后。在这两种情况下,UUID都是以块为单位生成的,形式为(块 ID; 随机数据)。块ID的大小取决于块的数量,并且是固定的(取决于生成器参数)。例如,对于默认值64 KB的块数量,需要使用2个字节来存储块ID。块ID定期增加,最终会发生回环。

  • 基于序列的UUID生成器可以使用带有256个UUID的块,计算两字节块ID:

    (nextval('s') / 256) % 65536
    说明
    • 生成器每生成16 M(256*65536)个UUID会回环一次。

    • 块大小由生成的UUID的数量决定。

  • 基于时间戳的UUID生成器默认的块数量是64 KB(与基于序列的生成器相同),计算块ID:

    (timestamp / 60) % 65536
    说明
    • 生成器约45天回环一次。

    • 块大小被定义为间隔长度,默认值为60秒。

UUID生成函数

sequential_uuid提供了两个生成具有顺序模式的UUID生成器的函数。一个使用序列,一个使用时间戳。

  • 函数uuid_sequence_nextval接收如下参数:

    • 一个regclass类型的对象(序列)。

    • 一个整数类型的块大小(默认值65536)。

    • 一个整数类型的块数量(默认值65536)。

    使用序列生成具有顺序模式的UUID生成器:

    CREATE EXTENSION sequential_uuids;
    CREATE SEQUENCE s;
    SELECT uuid_sequence_nextval('s'::regclass, 256, 65536);

    结果如下:

              uuid_sequence_nextval
    --------------------------------------
     00005547-8a67-452d-bdf7-b390f1edc49b
    (1 row)
  • 函数uuid_time_nextval接收如下参数:

    • 一个整数类型的时间间隔(默认值60)。

    • 一个整数类型的块数量(默认值65536)。

    使用时间戳生成具有顺序模式的UUID生成器:

    CREATE EXTENSION sequential_uuids;
    SELECT uuid_time_nextval(1, 256);

    结果如下:

              uuid_time_nextval
    --------------------------------------
     08dac705-8776-4ce3-a45c-123fd65e11e8
    (1 row)
说明

上述参数的默认值适用于绝大部分场景。