最近在研究pg序列的监控,对比记录一下pg列自增的各种实现方式。
对比项 | 分类 | 支持版本 | 创建时选项指定 | 多对象共享 | 可显式插入/更新列值 |
SEQUENCE | 对象类型 | 8.2 | 可以 | 可以 | 可以 |
SERIAL | 数据类型 | 7.1 | 不可以 | 不可以 | 可以 |
IDENTITY | 列属性 | 10 | 可以 | 不可以 | 视参数而定 |
本质上它们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 是一种对象类型,可以与多个表和列关联,且可以灵活定制各种选项。
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
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
有两个名字很像的,注意不要查错
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_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
PG 10 中为兼容标准SQL新加的语法,表示将列创建为标识列(自带NOT NULL)。
GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ]
本质上还是附加一个隐式序列并为其自动赋值,可以说是serial的增强版,实现了更多的功能。例如:
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标识列及存储列示例 - 墨天轮