华山论剑之 PostgreSQL sequence (一)
前言
本文是 sequence 系列继三大数据库 sequence 之华山论剑 (Oracle PostgreSQL MySQL sequence 十年经验总结) 之后的第二篇,主要分享一下 PostgreSQL 中关于 sequence 的一些经验。
测试环境准备
以下测试是在 PostgreSQL 11 中进行。
通过以下 SQL 创建:
测试用户: alvin,普通用户,非 superuser
测试数据库: alvindb,owner 是 alvin
测试 schema: alvin,owner 也是 alvin
这里采用的是 user 与 schema 同名,结合默认的 search_path
("$user", public),这样操作对象(table, sequence, etc.)时就不需要加 schema 前缀了。
postgres=# CREATE USER alvin WITH PASSWORD 'alvin';
CREATE ROLE
postgres=# CREATE DATABASE alvindb OWNER alvin;
CREATE DATABASE
postgres=# \c alvindb
You are now connected to database "alvindb" as user "postgres".
alvindb=# CREATE SCHEMA alvin AUTHORIZATION alvin;
CREATE SCHEMA
alvindb=# \c alvindb alvin
You are now connected to database "alvindb" as user "alvin".
alvindb=> SHOW search_path;
search_path
-----------------
"$user", public
(1 row)
创建 sequence 的两种方式
sequence 常规用途是用作主键序列的生成。下面通过通过创建 sequence 及表来讨论 sequence 创建方式。
创建 sequence 方式一 直接创建
下面是一种简单方式直接创建 sequence 及表。
alvindb=> CREATE SEQUENCE tb_test_sequence_test_id_seq;
CREATE SEQUENCE
alvindb=>
CREATE TABLE tb_test_sequence (
test_id INTEGER DEFAULT nextval('alvin.tb_test_sequence_test_id_seq') PRIMARY KEY,
create_time TIMESTAMP DEFAULT clock_timestamp()
);
CREATE TABLE
查看已创建的对象
alvindb=> \d
List of relations
Schema | Name | Type | Owner
--------+------------------------------+----------+-------
alvin | tb_test_sequence_test_id_seq | sequence | alvin
alvin | tb_test_sequence | table | alvin
(2 rows)
查看已创建对象的结构
alvindb=> \d tb_test_sequence
Table "alvin.tb_test_sequence"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+---------------------------------------------------
test_id | integer | | not null | nextval('tb_test_sequence_test_id_seq'::regclass)
create_time | timestamp without time zone | | | clock_timestamp()
Indexes:
"tb_test_sequence_pkey" PRIMARY KEY, btree (test_id)
alvindb=> \d tb_test_sequence_test_id_seq
Sequence "alvin.tb_test_sequence_test_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
alvindb=>
此时,我们会注意到,问题一,列 tb_test_sequence.test_id
的类型是 integer,而创建的 sequence 默认类型是 bigint。
这样没有问题,但如果类型一致的话会更好。
接下来,我们 drop sequence 的话,会发现,由于表依赖 sequence,所以不能单独 drop sequence。
alvindb=> DROP SEQUENCE tb_test_sequence_test_id_seq;
ERROR: cannot drop sequence tb_test_sequence_test_id_seq because other objects depend on it
DETAIL: default value for column test_id of table tb_test_sequence depends on sequence tb_test_sequence_test_id_seq
HINT: Use DROP ... CASCADE to drop the dependent objects too.
alvindb=>
下面我们 drop 掉表 tb_test_sequence
。
alvindb=> DROP TABLE tb_test_sequence;
DROP TABLE
alvindb=> \d
List of relations
Schema | Name | Type | Owner
--------+------------------------------+----------+-------
alvin | tb_test_sequence_test_id_seq | sequence | alvin
(1 row)
可以看到,问题二,虽然表 drop 了,但 sequence 还在。
这样会有什么问题呢?
在一个大型的数据库系统中,我们可能会发现有好多孤立的 sequence,因为我们 drop 表时可能会忘记 drop 掉其对应的 sequence。
现在先手动 drop 掉 sequence。
alvindb=> DROP SEQUENCE tb_test_sequence_test_id_seq;
DROP SEQUENCE
alvindb=> \d
Did not find any relations.
alvindb=>
我们优化一下 SQL 来解决上述两个问题:
alvindb=> CREATE SEQUENCE tb_test_sequence_test_id_seq AS INTEGER;
CREATE SEQUENCE
alvindb=>
CREATE TABLE tb_test_sequence (
test_id INTEGER DEFAULT nextval('alvin.tb_test_sequence_test_id_seq') PRIMARY KEY,
create_time TIMESTAMP DEFAULT clock_timestamp()
);
CREATE TABLE
alvindb=> ALTER SEQUENCE tb_test_sequence_test_id_seq OWNED BY tb_test_sequence.test_id;
ALTER SEQUENCE
上述 SQL 的作用是:
创建 sequence 时指定类型,使列与 sequence 的类型保持一致
关联表的列与 sequence,使 drop 表或列时会自动 drop 与其关联的 sequence
查看表结构,
alvindb=> \d tb_test_sequence
Table "alvin.tb_test_sequence"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+---------------------------------------------------
test_id | integer | | not null | nextval('tb_test_sequence_test_id_seq'::regclass)
create_time | timestamp without time zone | | | clock_timestamp()
Indexes:
"tb_test_sequence_pkey" PRIMARY KEY, btree (test_id)
alvindb=> \d tb_test_sequence_test_id_seq
Sequence "alvin.tb_test_sequence_test_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+---------+------------+-----------+---------+-------
integer | 1 | 1 | 2147483647 | 1 | no | 1
Owned by: alvin.tb_test_sequence.test_id
可以看到,
- 列
tb_test_sequence.test_id
与 sequence 的类型均为 integer - sequence 下方多了 'Owned by',表示列与 sequence 已关联了。
下面 drop 表后,可以看到,sequence 也已被 drop 了。
alvindb=> DROP TABLE tb_test_sequence;
DROP TABLE
alvindb=> \d
Did not find any relations.
实际上,如果 drop 掉列 test_id,其关联的 sequence 也会被 drop。
alvindb=> ALTER TABLE tb_test_sequence DROP COLUMN test_id;
ALTER TABLE
alvindb=> \d tb_test_sequence
Table "alvin.tb_test_sequence"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+-------------------
create_time | timestamp without time zone | | | clock_timestamp()
alvindb=> \d
List of relations
Schema | Name | Type | Owner
--------+------------------+-------+-------
alvin | tb_test_sequence | table | alvin
(1 row)
创建 sequence 方式二 通过 serial 创建
下面通过一个 SQL 来实现与上面完全相同的效果。
alvindb=>
CREATE TABLE tb_test_sequence (
test_id SERIAL PRIMARY KEY,
create_time TIMESTAMP DEFAULT clock_timestamp()
);
CREATE TABLE
查看表结构,与方式一中完全一样。
alvindb=> \d
List of relations
Schema | Name | Type | Owner
--------+------------------------------+----------+-------
alvin | tb_test_sequence | table | alvin
alvin | tb_test_sequence_test_id_seq | sequence | alvin
(2 rows)
alvindb=> \d tb_test_sequence
Table "alvin.tb_test_sequence"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+---------------------------------------------------
test_id | integer | | not null | nextval('tb_test_sequence_test_id_seq'::regclass)
create_time | timestamp without time zone | | | clock_timestamp()
Indexes:
"tb_test_sequence_pkey" PRIMARY KEY, btree (test_id)
alvindb=> \d tb_test_sequence_test_id_seq
Sequence "alvin.tb_test_sequence_test_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+---------+------------+-----------+---------+-------
integer | 1 | 1 | 2147483647 | 1 | no | 1
Owned by: alvin.tb_test_sequence.test_id
这里总结一下一个单词 SERIAL 做了什么事情:
- 根据规则
tablename_colname_seq
创建 sequence,并设置 DEFAULT - 增加 NOT NULL 约束
- 关联列与 sequence,使表或关联的列 drop 时,关联的 sequence 也会被 drop 掉
注:这里 SERIAL 和 PRIMARY KEY 之一都会默认增加 NOT NULL 约束
用 SERIAL 的确省了不少事,但它有什么问题吗?使用它会不会又引入了新的问题?
- SERIAL 对应的数据类型是 integer,作为主键的数据类型,integer 足够吗?
- 关联列与 sequence 后,drop 时是方便了,但同时会不会给运维带来新的问题?比如 rename 表,列或 sequence?
- 在复制表或迁移表时,又该对 sequence 作何操作呢?
接下来,我们从这几个问题出发进一步探讨。
serial 与 bigserial
serial 对应的是 integer,是 4 个字节,最大值是 2 147 483 647,即 21 亿左右。
作为大表主键的 sequence,21 亿真的够吗?按全球人口 70 亿算,一人一个数都不够。
为解决这个问题,可以用 bigserial,即 bigint,8 个字节,最大值是 9 223 372 036 854 775 807,即 922亿个亿左右。这对于绝大多数场景是足够了,这也是 PostgreSQL 中 sequence 的最大值。
使用 bigserial 创建表:
alvindb=>
CREATE TABLE tb_test_bigserial (
test_id BIGSERIAL PRIMARY KEY,
create_time TIMESTAMP DEFAULT clock_timestamp()
);
CREATE TABLE
查看表结构,
alvindb=> \d tb_test_bigserial
Table "alvin.tb_test_bigserial"
Column | Type | Collation | Nullable | Default
-------------+-----------------------------+-----------+----------+----------------------------------------------------
test_id | bigint | | not null | nextval('tb_test_bigserial_test_id_seq'::regclass)
create_time | timestamp without time zone | | | clock_timestamp()
Indexes:
"tb_test_bigserial_pkey" PRIMARY KEY, btree (test_id)
alvindb=> \d tb_test_bigserial_test_id_seq
Sequence "alvin.tb_test_bigserial_test_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
Owned by: alvin.tb_test_bigserial.test_id
可以看到,列 test_id
和 sequence 的 Type 都是 bigint。这样,sequence 的类型问题就解决了。
公众号
关注 DBA Daily 公众号,第一时间收到文章的更新。
通过一线 DBA 的日常工作,学习实用数据库技术干货!
公众号优质文章推荐
[PG Upgrade Series] Extract Epoch Trap
[PG Upgrade Series] Toast Dump Error
GitLab supports only PostgreSQL now
华山论剑之 PostgreSQL sequence (一)的更多相关文章
- 华山论剑之 PostgreSQL sequence (二)
rename 对 sequence 的影响 关联列与 sequence 后,即 sequence 属于该列后,drop 表或列时会自动 drop 相关 sequence. 但如果对表或列 rename ...
- 三大数据库 sequence 之华山论剑 (上篇)
前言 本文将基于以下三种关系型数据库,对 sequence (序列) 展开讨论. Oracle - 应用最广泛的商用关系型数据库 PostgreSQL - 功能最强大的开源关系型数据库 MySQL - ...
- 三大数据库 sequence 之华山论剑 (中篇)
sequence 用法四 AUTO INCREMENT 通过 DEFAULT 还是需要手动创建 sequence.有没有更简单的用法呢? 当然,就是通过 AUTO INCREMENT 方式,自动创建 ...
- 三大数据库 sequence 之华山论剑 (下篇)
MySQL 5.7 MYISAM ENGINE 以下是 MySQL 5.7 MYISAM ENGINE 中的运行结果 mysql> CREATE TABLE tb_test5 ( -> t ...
- PostgreSQL VACUUM 之深入浅出 (一)
前言 VACUUM 是 PostgreSQL MVCC (Multiversion concurrency control) 实现的核心机制之一,是 PostgreSQL 正常运行的重要保证.本文将通 ...
- PostgreSQL VACUUM 之深入浅出 (二)
AUTOVACUUM AUTOVACUUM 简介 PostgreSQL 提供了 AUTOVACUUM 的机制. autovacuum 不仅会自动进行 VACUUM,也会自动进行 ANALYZE,以分析 ...
- PostgreSQL VACUUM 之深入浅出 (三)
VACUUM 相关参数 对 VACUUM 有了一定的了解之后,下面系统介绍下 VACUUM 相关参数. VACUUM 相关参数主要分为三大类. 第一类 与资源相关参数 #--------------- ...
- PostgreSQL VACUUM 之深入浅出 (四)
VACUUM 参数优化 上面已经介绍过了以下设置表级 AUTOVACUUM 相关参数和 autovacuum_max_workers: ALTER TABLE pgbench_accounts SET ...
- PostgreSQL 9.1 飞升之路
PostgreSQL upgrade 以升级 PostgreSQL 9.1 至 PostgreSQL 11 (跨越 9.2.9.3.9.4.9.5.9.6.10 六个大版本) 为例,本文将分享一下过去 ...
随机推荐
- Python初学笔记之字符串
一.字符串的定义 字符串是就一堆字符,可以使用""(双引号).''(单引号)来创建. 1 one_str = "定义字符串" 字符串内容中包含引号时,可以使用转 ...
- 1. idea spark scala 语言支持设置
Spark 版本为 3.0.0,默认采用的 Scala 编译版本为 2.12 1. 创建名为spark-project 的项目 2. 将src 删除,把spark-project 当成一个父项目, ...
- springboot 分布式项目,子级项目各自的作用。
一.分布式项目,需要使用maven搭建. 1.1 父级pro.xml module. <?xml version="1.0" encoding="UTF-8&quo ...
- Atcoder ARC-062
ARC062(2020.7.13) A 可以考虑直接同时扩大这次的两个票数,那么使得两数均大于之前位置的票数就是最优的,扩大的话直接除一下上取整即可. B 贪心即可. C 可以发现这个东西如果直接计数 ...
- java实现以docx格式导出
直接上代码:Map<String, Object> dataMap = afterLoanReportService.exportReport(startDate, endDate);// ...
- Guava学习之EventBus
一.EventBus的使用案例 EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现.对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单 ...
- HTML页元素自适应+居中总结(不定期补充)
感谢大佬:https://www.cnblogs.com/SallyShan/p/11480685.html 图片自适应 背景图片自适应 /*背景页*/ #page_content{ width: 1 ...
- War包是什么??
感谢大佬: https://blog.csdn.net/Stitch__/article/details/88091745 https://www.jianshu.com/p/3b5c45e8e5bd ...
- @property中的copy关键字
1.@property中的copy的作用 防止外界修改内部的值 @interface Person : NSObject @property (nonatomic, retain) NSString ...
- php栈的定义及入栈出栈的实现 算法
转自:php栈的定义及入栈出栈的实现 栈是线性表的一种,他的特点是后入先出,可以这么理解,栈就像一个存东西的盒子,先放进去的在最底层,后放进去的在上层,因为上层的东西把底层的东西压住了,下层的想要出去 ...