由PG序列监控,看三种列自增方式

       最近在研究pg序列的监控,对比记录一下pg列自增的各种实现方式。

一、 对比概要

1. 相同点

  • 三种方法本质上都是序列,因此大多数特性都是相同的
  • 均可通过 pg_sequences 视图查询信息 
  • 显式插入/导入数据后,序列最大值不会自动更新
  • 可以手动设置序列值
  • truncate table 序列值不会重置
  • 回滚事务序列值不会回退

2. 主要区别

对比项 分类 支持版本 创建时选项指定 多对象共享 可显式插入/更新列值
SEQUENCE 对象类型 8.2 可以 可以 可以
SERIAL 数据类型 7.1 不可以 不可以 可以
IDENTITY 列属性 10 可以 不可以 视参数而定

3. 使用率监控

       本质上它们3个都是序列,因此在 pg_sequences 视图中全都能查到。对于整个实例而言,只要看使用率最高的一个序列即可。

SELECT 
max(
CASE WHEN increment_by<0
 THEN round(last_value/min_value*100,4)
WHEN increment_by>0
  THEN round(last_value/max_value*100,4)
 ELSE 0
  END 
) AS pct_seq_used
from pg_sequences 
WHERE cycle='f';

二、 SEQUENCE

       SEQUENCE 是一种对象类型,可以与多个表和列关联,且可以灵活定制各种选项

1. 定义

CREATE [ TEMPORARY | TEMP ] SEQUENCE [ IF NOT EXISTS ] name
    [ AS data_type ]
    [ INCREMENT [ BY ] increment ]
    [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
    [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
    [ OWNED BY { table_name.column_name | NONE } ]
postgres=# CREATE SEQUENCE seq_a INCREMENT 2 START 101;
CREATE SEQUENCE

2. 相关函数

  • nextval():获取指定序列的下一个值(由INCREMENT参数确定)。
  • currval():获取当前会话的最新序列值(注意不是数据库中的最新序列值),因此如果是新会话,直接调用本函数会报错。
  • setval():将序列当前值设置为指定值,可以往前也可以往后,但一般是往前。
postgres=# CREATE SEQUENCE seq_a INCREMENT 2 START 101;
CREATE SEQUENCE

postgres=# SELECT nextval('seq_a');
 nextval 
---------
     101
(1 row)

postgres=# SELECT currval('seq_a');
 currval 
---------
     101
(1 row)

postgres=# SELECT setval('seq_a',500);
 setval 
--------
    500
(1 row)

postgres=# SELECT currval('seq_a');
 currval 
---------
     500
(1 row)

开一个新会话

-bash-4.2$ psql
psql (14.0)
Type "help" for help.

postgres=# SELECT currval('seq_a');
ERROR:  currval of sequence "seq_a" is not yet defined in this session

3. 相关视图

有两个名字很像的,注意不要查错

  • pg_sequence:存储序列基础信息,不太易读,一般不用
  • pg_sequences:易读版的序列信息,常用

4. 特性

  • 序列基于bigint(8 byte),因此其范围为 [-2^63,2^63-1]
  • 在有cache的情况下,sequence只保证每次获取到的数字都是唯一、递增的,不保证连续性

三、 serial

       serial是一种伪数据类型,与单列绑定,不能直接指定选项。它不是真正的数据类型,只是一种用于创建唯一标识符列的便利表示(类似mysql的AUTO_INCREMENT)。

       可以细分为3种:smallserial,serial,bigserial,上限分别对应smallint,int,bigint的最大值。

       本质上它的原理是,在创建表结构时由pg自动创建一个序列,并将序列赋给对应字段,因此它大部分特性都与序列类似。根据官方文档:

CREATE TABLE ser_table (
    a SERIAL
);

-- is equivalent to specifying:

CREATE SEQUENCE tablename_colname_seq AS integer;
CREATE TABLE tablename (
    colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

创建案例

CREATE TABLE ser_table (
a SERIAL,
b int
);

\d ser_table

insert into ser_table(b) values(1);
insert into ser_table(b) values(1);
insert into ser_table(b) values(1);

select * from ser_table;

由PG序列监控,看三种列自增方式_第1张图片

使用pg_get_serial_sequence函数可以获得serial列的序列名称:

postgres=# select pg_get_serial_sequence('ser_table','a');
 pg_get_serial_sequence 
------------------------
 public.ser_table_a_seq
(1 row)

查看SERIAL使用情况,依然是用序列的视图

postgres=# SELECT * FROM pg_sequences where sequencename='ser_table_a_seq';
-[ RECORD 1 ]-+----------------
schemaname    | public
sequencename  | ser_table_a_seq
sequenceowner | postgres
data_type     | integer
start_value   | 1
min_value     | 1
max_value     | 2147483647
increment_by  | 1
cycle         | f
cache_size    | 1
last_value    | 3

四、 identity列

PG 10 中为兼容标准SQL新加的语法,表示将列创建为标识列(自带NOT NULL)。

GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]

       本质上还是附加一个隐式序列并为其自动赋值,可以说是serial的增强版,实现了更多的功能。例如:

  • 可以通过alter table直接设置或取消标识列
  • 标识列值可以手动回退
  • 语法中的 ALWAYS 和 BY DEFAULT 子句确定了在 INSERT 和 UPDATE 命令中如何处理用户指定的值
  • 可选的 sequence_options 子句可用于覆盖序列的选项
  • CTAS 命令复制表会使用不同的序列
  • 表删除 default 属性时会同步删除序列
  • 不需对序列进行额外赋权
CREATE TABLE cars (
    car_id INT GENERATED ALWAYS AS IDENTITY,
    brand_name VARCHAR NOT NULL
);

INSERT INTO CARS(brand_name) VALUES('Honda');

-- 还可以通过将 card_id 定义为 DEFAULT 来添加数据。
INSERT INTO CARS(car_id, brand_name) VALUES(DEFAULT, 'Jeep');

-- 如果通过插入car_id而不是使用系统生成的数据,则会报错。

INSERT INTO CARS(car_id, brand_name) VALUES(5, 'Tesla');

-- 要修复此错误,可以用OVERRIDING SYSTEM VALUE 子句
INSERT INTO CARS(car_id, brand_name) OVERRIDING SYSTEM VALUE 
VALUES(5, 'Tesla');

GENERATED BY DEFAULT AS IDENTITY 子句与GENERATED ALWAYS AS IDENTITY做同样的事情,唯一的区别是您可以手动插入标识列的值而不覆盖它,并且不会引发错误。

CREATE TABLE cars (
    car_id INT GENERATED BY DEFAULT AS IDENTITY,
    brand_name VARCHAR NOT NULL
);

INSERT INTO CARS(car_id, brand_name) VALUES(5, 'Tesla');

IDENTITY列可以使用序列选项

CREATE TABLE cars (
    car_id INT GENERATED BY DEFAULT AS IDENTITY
        (START WITH 10 INCREMENT BY 5),
    brand_name VARCHAR NOT NULL
);

INSERT INTO CARS(brand_name) VALUES('Honda');
INSERT INTO CARS(car_id, brand_name) VALUES(DEFAULT, 'Jeep');

pg将使用指定的序列并生成 car_id 值,从 10 开始并将其递增 5

可以使用 ALTER TABLE 语句更改现有标识列的特征。

以下会将标识列从GENERATED ALWAYS更改为 GENERATED BY DEFAULT。

ALTER TABLE CARS ALTER COLUMN car_id SET GENERATED BY DEFAULT;

删除身份约束
GENERATED AS IDENTITY可以从表的列中删除约束,而无需使用ALTER TABLE ALTER COLUMN语句删除列。

ALTER TABLE CARS ALTER COLUMN car_id DROP IDENTITY IF EXISTS;

参考

https://www.cnblogs.com/wy123/p/13367486.html
​​​​​​PostgreSQL标识列及存储列示例 - 墨天轮

你可能感兴趣的:(PostgreSQL,监控,postgresql,自增,序列,监控,identity)