162 lines
4.4 KiB
Markdown
162 lines
4.4 KiB
Markdown
# PostgreSQL SEQUENCE(序列)详解
|
||
|
||
## 语句解析
|
||
|
||
```sql
|
||
DROP SEQUENCE IF EXISTS "public"."adm_encounter_id_seq";
|
||
CREATE SEQUENCE "public"."adm_encounter_id_seq"
|
||
INCREMENT 1
|
||
MINVALUE 1
|
||
MAXVALUE 99999999
|
||
START 200
|
||
CACHE 1;
|
||
```
|
||
|
||
## 逐行解释
|
||
|
||
### 1. `DROP SEQUENCE IF EXISTS "public"."adm_encounter_id_seq";`
|
||
- **作用**:如果序列已存在,先删除它
|
||
- **`IF EXISTS`**:如果序列不存在,不会报错,直接跳过
|
||
- **`"public"."adm_encounter_id_seq"`**:序列的完整名称
|
||
- `public`:模式(schema)名,默认模式
|
||
- `adm_encounter_id_seq`:序列名称
|
||
|
||
### 2. `CREATE SEQUENCE "public"."adm_encounter_id_seq"`
|
||
- **作用**:创建一个新的序列
|
||
- **序列名称**:`adm_encounter_id_seq`(用于 `adm_encounter` 表的主键自增)
|
||
|
||
### 3. `INCREMENT 1`
|
||
- **作用**:每次递增的步长
|
||
- **含义**:每次调用 `nextval()` 时,序列值增加 1
|
||
- **示例**:如果当前值是 200,下次调用 `nextval()` 返回 201
|
||
|
||
### 4. `MINVALUE 1`
|
||
- **作用**:序列的最小值
|
||
- **含义**:序列值不能小于 1
|
||
- **注意**:如果序列达到最小值后继续递减,会报错(除非设置了 `CYCLE`)
|
||
|
||
### 5. `MAXVALUE 99999999`
|
||
- **作用**:序列的最大值
|
||
- **含义**:序列值不能超过 99999999(8位数)
|
||
- **注意**:如果序列达到最大值后继续递增,会报错(除非设置了 `CYCLE`)
|
||
|
||
### 6. `START 200`
|
||
- **作用**:序列的起始值
|
||
- **含义**:序列从 200 开始
|
||
- **示例**:第一次调用 `nextval()` 返回 200,第二次返回 201,以此类推
|
||
|
||
### 7. `CACHE 1`
|
||
- **作用**:缓存大小
|
||
- **含义**:每次从数据库获取序列值时,预分配 1 个值到内存
|
||
- **说明**:
|
||
- `CACHE 1`:每次只缓存 1 个值(最安全,但性能较低)
|
||
- `CACHE 20`:每次缓存 20 个值(性能更好,但可能跳号)
|
||
- **注意**:如果数据库重启,缓存中未使用的序列值会丢失,导致跳号
|
||
|
||
## 使用示例
|
||
|
||
### 1. 在表定义中使用(自动自增)
|
||
```sql
|
||
CREATE TABLE "adm_encounter" (
|
||
"id" int8 NOT NULL DEFAULT nextval('adm_encounter_id_seq'::regclass),
|
||
...
|
||
);
|
||
```
|
||
|
||
### 2. 手动获取下一个值
|
||
```sql
|
||
-- 获取下一个序列值
|
||
SELECT nextval('adm_encounter_id_seq');
|
||
-- 返回:200(第一次调用)
|
||
|
||
SELECT nextval('adm_encounter_id_seq');
|
||
-- 返回:201(第二次调用)
|
||
```
|
||
|
||
### 3. 查看当前值(不递增)
|
||
```sql
|
||
SELECT currval('adm_encounter_id_seq');
|
||
-- 返回:当前序列值(不会增加)
|
||
```
|
||
|
||
### 4. 重置序列
|
||
```sql
|
||
-- 将序列重置为指定值
|
||
SELECT setval('adm_encounter_id_seq', 200);
|
||
```
|
||
|
||
## 实际应用场景
|
||
|
||
### 场景1:插入数据时自动生成ID
|
||
```sql
|
||
INSERT INTO adm_encounter (patient_id, organization_id, ...)
|
||
VALUES (123, 456, ...);
|
||
-- id 字段会自动使用序列的下一个值(如 200, 201, 202...)
|
||
```
|
||
|
||
### 场景2:手动指定ID(不推荐)
|
||
```sql
|
||
INSERT INTO adm_encounter (id, patient_id, ...)
|
||
VALUES (999, 123, ...);
|
||
-- 注意:如果手动插入的ID与序列值冲突,可能导致问题
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
### 1. 序列与雪花算法的区别
|
||
- **序列**:简单的数字递增(1, 2, 3...)
|
||
- **雪花算法**:分布式ID生成算法(如:1996923066055286785)
|
||
- **当前项目**:虽然定义了序列,但实际使用的是雪花算法(`IdType.ASSIGN_ID`)
|
||
|
||
### 2. 序列跳号的原因
|
||
- 事务回滚:如果事务回滚,序列值不会回退
|
||
- 缓存:`CACHE > 1` 时,数据库重启可能导致跳号
|
||
- 手动插入:手动插入ID后,序列不会自动调整
|
||
|
||
### 3. 序列的优缺点
|
||
**优点**:
|
||
- 简单易用
|
||
- 性能好(预分配)
|
||
- 保证唯一性
|
||
|
||
**缺点**:
|
||
- 可能跳号
|
||
- 不适合分布式环境
|
||
- 最大值有限制
|
||
|
||
## 相关查询语句
|
||
|
||
### 查看序列信息
|
||
```sql
|
||
-- 查看序列的详细信息
|
||
SELECT
|
||
sequence_name AS 序列名称,
|
||
last_value AS 当前值,
|
||
start_value AS 起始值,
|
||
increment_by AS 递增步长,
|
||
max_value AS 最大值,
|
||
min_value AS 最小值,
|
||
cache_size AS 缓存大小
|
||
FROM information_schema.sequences
|
||
WHERE sequence_name = 'adm_encounter_id_seq';
|
||
```
|
||
|
||
### 查看序列的下一个值(不实际使用)
|
||
```sql
|
||
SELECT last_value, is_called
|
||
FROM adm_encounter_id_seq;
|
||
```
|
||
|
||
### 修改序列
|
||
```sql
|
||
-- 修改序列的起始值
|
||
ALTER SEQUENCE adm_encounter_id_seq RESTART WITH 1000;
|
||
|
||
-- 修改序列的最大值
|
||
ALTER SEQUENCE adm_encounter_id_seq MAXVALUE 999999999;
|
||
|
||
-- 修改序列的缓存大小
|
||
ALTER SEQUENCE adm_encounter_id_seq CACHE 20;
|
||
```
|
||
|