PostgreSQL序列用法小結(jié)
PostgreSQL 中的序列(Sequence)是一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)對(duì)象,專門用于生成唯一的遞增整數(shù),最常用于為表字段生成自增主鍵。下面詳細(xì)解析序列的用法、核心函數(shù)以及實(shí)戰(zhàn)中的避坑指南。
??? 序列的基本操作
1. 創(chuàng)建自定義序列
可以使用 CREATE SEQUENCE 語(yǔ)句來(lái)創(chuàng)建一個(gè)完全可控的序列:
-- 基本語(yǔ)法 CREATE SEQUENCE 序列名 [INCREMENT BY 步長(zhǎng)] -- 默認(rèn)為1,可設(shè)為負(fù)數(shù)(遞減) [START WITH 起始值] -- 默認(rèn)為1 [MINVALUE 最小值] -- 默認(rèn)為1(遞增時(shí)) [MAXVALUE 最大值] -- 默認(rèn)為 2^31-1(int類型) [CACHE 緩存數(shù)量] -- 緩存序列值以提高性能,默認(rèn)1 [CYCLE | NO CYCLE]; -- 達(dá)到最大值后是否循環(huán),默認(rèn)不循環(huán) -- 示例:創(chuàng)建從100開(kāi)始,步長(zhǎng)為2,不設(shè)置最大值的序列 CREATE SEQUENCE test_seq START WITH 100 INCREMENT BY 2 NO MAXVALUE CACHE 1;
2. 將序列與表關(guān)聯(lián)
在創(chuàng)建表時(shí),或者為已存在的表添加自增屬性時(shí),可以將序列綁定到字段上:
-- 創(chuàng)建表時(shí)關(guān)聯(lián)序列
CREATE TABLE test_table (
id INT PRIMARY KEY DEFAULT nextval('test_seq'),
-- 插入時(shí)自動(dòng)取序列值
content TEXT
);
-- 為已存在的表關(guān)聯(lián)序列
ALTER TABLE existing_table
ALTER COLUMN id SET DEFAULT nextval('test_seq');3. 刪除序列
DROP SEQUENCE IF EXISTS test_seq; -- 如果序列被表引用,可以使用 CASCADE 強(qiáng)制刪除并解除依賴 DROP SEQUENCE IF EXISTS test_seq CASCADE;
4. 修改序列
??? 使用 ALTER SEQUENCE 修改序列屬性
ALTER SEQUENCE 命令可以靈活地修改序列的各項(xiàng)參數(shù),包括重置起始值、調(diào)整步長(zhǎng)、修改最大/最小值等6。
- 重置序列的下一個(gè)值(最常用)
使用RESTART WITH可以改變序列下一次調(diào)用nextval()時(shí)返回的值2。
-- 將序列的下一個(gè)值重置為 1
ALTER SEQUENCE 序列名 RESTART WITH 1;
- 修改步長(zhǎng)、最大值、最小值等屬性
可以一次性修改序列的多個(gè)屬性:
ALTER SEQUENCE 序列名
INCREMENT BY 2 -- 修改步長(zhǎng)為 2
MAXVALUE 1000000 -- 修改最大值為 100萬(wàn)
MINVALUE 0 -- 修改最小值為 0
CACHE 10 -- 修改緩存數(shù)量為 10
CYCLE; -- 開(kāi)啟達(dá)到最大值后循環(huán)- 修改序列的歸屬或擁有者
可以將序列綁定到某個(gè)表的特定字段(刪除該字段時(shí)序列會(huì)自動(dòng)刪除),或者修改序列的所有者
-- 將序列綁定到指定表的指定字段
ALTER SEQUENCE 序列名 OWNED BY 表名.字段名;
-- 解除序列與任何字段的綁定
ALTER SEQUENCE 序列名 OWNED BY NONE;
-- 修改序列的擁有者 ALTER SEQUENCE 序列名 OWNER TO 新用戶名;- 修改序列的名稱或模式
-- 修改序列名
ALTER SEQUENCE 序列名 RENAME TO 新序列名;
-- 將序列移動(dòng)到另一個(gè) Schema 下
ALTER SEQUENCE 序列名 SET SCHEMA 新Schema名;
- 使用
setval()函數(shù)動(dòng)態(tài)調(diào)整當(dāng)前值
如果需要根據(jù)表中現(xiàn)有的數(shù)據(jù)來(lái)動(dòng)態(tài)調(diào)整序列(例如防止主鍵沖突),使用 setval() 函數(shù)會(huì)更加方便。
設(shè)置為固定值
-- 將序列的當(dāng)前值直接設(shè)置為 1000,下一次 nextval 將返回 1001
SELECT setval('序列名', 1000);
基于表中最大 ID 動(dòng)態(tài)同步(強(qiáng)烈推薦)
當(dāng)手動(dòng)插入過(guò)數(shù)據(jù)導(dǎo)致序列與表數(shù)據(jù)不匹配時(shí),可以使用此方法完美解決:
-- 將序列的當(dāng)前值同步為表中的最大 ID,避免下次插入時(shí)主鍵沖突
SELECT setval('序列名', (SELECT COALESCE(MAX(id), 0) FROM 表名));
?? 溫馨提示
- 權(quán)限要求:執(zhí)行 ALTER SEQUENCE 或 setval() 操作,必須是該序列的所有者。
- 事務(wù)特性:ALTER SEQUENCE 的大部分操作(如 RESTART)是不可回滾的;而 setval() 在事務(wù)中是可以被回滾的。
- 并發(fā)影響:ALTER SEQUENCE 在修改期間會(huì)阻塞 nextval、setval 等函數(shù)的調(diào)用,建議在業(yè)務(wù)低峰期執(zhí)行。
?? 序列的核心操作函數(shù)
PostgreSQL 提供了一系列函數(shù)來(lái)操作和獲取序列值:
| 函數(shù) | 作用 | 示例 |
|---|---|---|
| nextval(序列名) | 生成并返回下一個(gè)序列值(自動(dòng)遞增) | SELECT nextval('test_seq'); |
| currval(序列名) | 獲取當(dāng)前會(huì)話中最后一次生成的序列值 | SELECT currval('test_seq'); |
| lastval() | 獲取當(dāng)前會(huì)話中最后一次生成的任意序列值 | SELECT lastval(); |
| setval(序列名, 值) | 直接設(shè)置序列的當(dāng)前值 | SELECT setval('test_seq', 200); |
- nextval() :最常用且最安全,即使在未提交的事務(wù)中調(diào)用也會(huì)消耗一個(gè)號(hào)(事務(wù)回滾后不退還)。
- currval() :前提是當(dāng)前會(huì)話必須先調(diào)用過(guò) nextval(),否則會(huì)報(bào)錯(cuò)。常用于插入主表后,立即用該 ID 插入關(guān)聯(lián)的子表。
- lastval() :慎用! 如果中間調(diào)用了其他序列,lastval() 返回的會(huì)是其他序列的值,在觸發(fā)器或復(fù)雜函數(shù)中極易出錯(cuò)。
?? 實(shí)戰(zhàn)中的三種自增主鍵實(shí)現(xiàn)方式
在實(shí)際開(kāi)發(fā)中,有三種常見(jiàn)的方式來(lái)實(shí)現(xiàn)自增主鍵,推薦程度依次遞增:
1. 手動(dòng)創(chuàng)建并綁定序列(最靈活)
如上文所示,手動(dòng)創(chuàng)建序列后,在表定義中通過(guò) DEFAULT nextval('序列名') 來(lái)使用。這種方式適合需要多個(gè)表共享同一個(gè)序列的場(chǎng)景。
2. 使用 SERIAL / BIGSERIAL(快捷方式)
SERIAL 并不是真實(shí)的數(shù)據(jù)類型,而是 PostgreSQL 提供的語(yǔ)法糖(快捷方式)。它會(huì)自動(dòng)為創(chuàng)建一個(gè)序列,并將其綁定到字段上。
- SERIAL 等價(jià)于 INTEGER + 自動(dòng)序列
- BIGSERIAL 等價(jià)于 BIGINT + 自動(dòng)序列(推薦,防止數(shù)據(jù)量大時(shí)溢出)
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY, -- 自動(dòng)創(chuàng)建 users_id_seq 并關(guān)聯(lián)
username VARCHAR(50) NOT NULL
);
3. 使用 IDENTITY 列(SQL標(biāo)準(zhǔn),強(qiáng)烈推薦 ?) 從 PostgreSQL 10 開(kāi)始,引入了符合 SQL 標(biāo)準(zhǔn)的 GENERATED AS IDENTITY。它的語(yǔ)義更清晰,明確表示“此列由系統(tǒng)生成”,且工具兼容性更好
CREATE TABLE products (
id BIGINT GENERATED ALWAYS AS IDENTITY (
START WITH 1000
INCREMENT BY 1
CACHE 10
) PRIMARY KEY,
name TEXT NOT NULL
);
?? 避坑指南與性能優(yōu)化
- ID 不連續(xù)與事務(wù)回滾
序列值一旦被nextval()獲取,即使所在的事務(wù)回滾,這個(gè)值也不會(huì)被回收。因此,序列生成的 ID 可能會(huì)出現(xiàn)跳號(hào)(不連續(xù))的情況,業(yè)務(wù)邏輯中不要強(qiáng)依賴 ID 的連續(xù)性。 - 手動(dòng)插入 ID 導(dǎo)致的主鍵沖突
如果手動(dòng)向表中插入了指定的 ID(例如INSERT INTO users (id, name) VALUES (999, '張三')),序列的當(dāng)前值并不會(huì)自動(dòng)更新。下次自動(dòng)插入時(shí)可能會(huì)因?yàn)?ID 重復(fù)而報(bào)錯(cuò)。
解決方法:手動(dòng)同步序列值為表中的最大 ID。
SELECT setval('users_id_seq',
(SELECT COALESCE(MAX(id), 0) FROM users));
- 高并發(fā)下的性能優(yōu)化(CACHE)
在并發(fā)量高的場(chǎng)景下,頻繁獲取序列值會(huì)產(chǎn)生爭(zhēng)用(Sequence Contention)??梢酝ㄟ^(guò)增大CACHE值來(lái)優(yōu)化,序列會(huì)預(yù)分配一批值到內(nèi)存中,減少磁盤 I/O。例如CACHE 1000適合高并發(fā)場(chǎng)景,但缺點(diǎn)是數(shù)據(jù)庫(kù)異常崩潰時(shí),內(nèi)存中未使用的緩存序列號(hào)會(huì)丟失,導(dǎo)致 ID 出現(xiàn)更大的跳躍。
-- 高并發(fā)場(chǎng)景推薦配置
CREATE SEQUENCE high_perf_seq
CACHE 1000
NO CYCLE;
?? ALTER SEQUENCE 影響關(guān)聯(lián)的表?
ALTER SEQUENCE 對(duì)關(guān)聯(lián)表的影響,主要取決于具體修改了序列的哪個(gè)屬性??傮w來(lái)說(shuō),它的影響可以分為“生命周期綁定”和“數(shù)據(jù)生成影響”兩個(gè)層面:
1. 修改序列的歸屬關(guān)系(OWNED BY)
這是 ALTER SEQUENCE 對(duì)關(guān)聯(lián)表最直接的影響。通過(guò) OWNED BY 子句,可以將序列與表的特定字段進(jìn)行綁定或解綁:
- 建立綁定:當(dāng)執(zhí)行 ALTER SEQUENCE 序列名 OWNED BY 表名.字段名; 后,序列就和該字段“同生共死”了。如果將來(lái)刪除了這個(gè)字段或者刪除了整張表,PostgreSQL 會(huì)自動(dòng)將該序列一并刪除。
- 解除綁定:執(zhí)行 ALTER SEQUENCE 序列名 OWNED BY NONE; 會(huì)切斷這種聯(lián)系,使序列變成一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)對(duì)象,刪除表時(shí)不再影響它。
2. 修改序列的生成規(guī)則(如MAXVALUE,RESTART等)
當(dāng)修改序列的步長(zhǎng)、最大值、起始值等屬性時(shí),不會(huì)改變表的結(jié)構(gòu),也不會(huì)修改表中已經(jīng)存在的數(shù)據(jù)。它的影響主要體現(xiàn)在未來(lái)插入的新數(shù)據(jù)上:
對(duì)現(xiàn)有數(shù)據(jù)無(wú)影響:修改序列的最大值或重置序列值,絕對(duì)不會(huì)更新或刪除表中已經(jīng)生成的 ID。
對(duì)后續(xù)插入的影響:
- RESTART WITH / setval() :如果將序列重置為一個(gè)較小的值(例如表中已經(jīng)存在的 ID),那么下次向表中插入數(shù)據(jù)時(shí),會(huì)因?yàn)橹麈I重復(fù)而報(bào)錯(cuò)(主鍵沖突)。
- MAXVALUE:如果將最大值改得比當(dāng)前序列值還小,或者設(shè)置了 NO CYCLE(不循環(huán))且序列達(dá)到了新的上限,后續(xù)的插入操作會(huì)因?yàn)闊o(wú)法獲取新的序列值而報(bào)錯(cuò)。
性能與并發(fā)影響:
- 阻塞調(diào)用:執(zhí)行 ALTER SEQUENCE 命令期間,會(huì)短暫阻塞并發(fā)的 nextval、currval 等函數(shù)調(diào)用。在高并發(fā)的業(yè)務(wù)高峰期執(zhí)行可能會(huì)造成短暫的請(qǐng)求卡頓。
- 清空緩存:如果修改了序列的最大值(MAXVALUE),數(shù)據(jù)庫(kù)會(huì)清空該序列在所有會(huì)話中的緩存(Cache)。這可能導(dǎo)致序列生成出現(xiàn)較大的跳號(hào),并短暫影響獲取序列值的性能。
3. 修改序列的其他屬性(擁有者、名稱等)
- OWNER TO / RENAME TO:修改序列的擁有者或重命名序列,對(duì)關(guān)聯(lián)的表沒(méi)有任何邏輯上的影響。表依然可以通過(guò)內(nèi)部依賴正常調(diào)用該序列(即使改了名,PostgreSQL 也能通過(guò) OID 識(shí)別)。
總結(jié)建議:
如果只是修改序列的生成規(guī)則,只要確保新規(guī)則不會(huì)導(dǎo)致主鍵沖突或超出范圍,對(duì)關(guān)聯(lián)表就是安全的。如果涉及到 OWNED BY 的綁定操作,則需要考慮到未來(lái)刪除表時(shí)的連帶效應(yīng)。
?? ALTER SEQUENCE 影響正在運(yùn)行的事務(wù)?
ALTER SEQUENCE 對(duì)正在運(yùn)行的事務(wù)確實(shí)有影響,但這種影響并不是“一刀切”的,而是分為“立即生效”和“延遲生效”兩種情況。具體取決于修改的是序列的哪部分屬性:
?? 立即生效且不可回滾(影響序列生成參數(shù))
當(dāng)修改序列的生成參數(shù)(例如 RESTART WITH、INCREMENT BY、MAXVALUE、MINVALUE、CYCLE 等)時(shí):
- 不可回滾:為了避免多個(gè)并發(fā)事務(wù)在獲取序列值時(shí)互相阻塞,這些修改會(huì)立即生效且無(wú)法通過(guò)事務(wù)回滾(ROLLBACK)撤銷。
- 阻塞并發(fā)調(diào)用:
ALTER SEQUENCE在執(zhí)行期間會(huì)直接阻塞其他并發(fā)事務(wù)對(duì)nextval、currval、lastval和setval等函數(shù)的調(diào)用。這意味著如果的業(yè)務(wù)正處于高并發(fā)狀態(tài),執(zhí)行這些修改可能會(huì)導(dǎo)致短暫的請(qǐng)求卡頓。 - 當(dāng)前會(huì)話立即生效:執(zhí)行命令的當(dāng)前數(shù)據(jù)庫(kù)會(huì)話(后端)會(huì)立刻受到影響,使用新的參數(shù)生成序列值。
?? 延遲生效(受緩存 Cache 影響)
如果為序列設(shè)置了緩存(CACHE 參數(shù)大于 1),其他正在運(yùn)行的事務(wù)(后臺(tái)會(huì)話)可能會(huì)受到影響:
- 緩存耗盡后才生效:其他事務(wù)在修改發(fā)生前可能已經(jīng)預(yù)分配(緩存)了一批序列值在內(nèi)存中。它們會(huì)繼續(xù)使用完這些緩存的值,直到緩存用盡后,才會(huì)感知并采用修改后的新序列參數(shù)。
? 可回滾的普通更新(影響元數(shù)據(jù))
當(dāng)修改序列的元數(shù)據(jù)屬性(例如 OWNED BY、OWNER TO、RENAME TO、SET SCHEMA)時(shí):
- 支持事務(wù)回滾:這些操作屬于普通的系統(tǒng)目錄更新,可以被事務(wù)回滾。如果在一個(gè)事務(wù)中修改了序列的名字或歸屬,隨后執(zhí)行了
ROLLBACK,這些改動(dòng)會(huì)被撤銷。 - 同樣會(huì)阻塞調(diào)用:盡管支持回滾,但這些元數(shù)據(jù)修改操作在執(zhí)行時(shí),同樣會(huì)阻塞并發(fā)的
nextval等序列函數(shù)調(diào)用5。
?? 核心總結(jié)與建議
- 對(duì)現(xiàn)有數(shù)據(jù)無(wú)影響:無(wú)論哪種修改,都絕對(duì)不會(huì)影響表中已經(jīng)存在的數(shù)據(jù),也不會(huì)影響序列的
currval狀態(tài)(當(dāng)前會(huì)話最后一次獲取的值)。 - 避開(kāi)業(yè)務(wù)高峰期:由于
ALTER SEQUENCE在執(zhí)行期間會(huì)阻塞并發(fā)的序列值獲取操作,強(qiáng)烈建議在業(yè)務(wù)低峰期或維護(hù)窗口執(zhí)行該命令,以避免對(duì)線上正在運(yùn)行的事務(wù)造成卡頓或性能抖動(dòng)。
到此這篇關(guān)于PostgreSQL序列用法小結(jié)的文章就介紹到這了,更多相關(guān)PostgreSQL序列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- PostgreSQL數(shù)據(jù)庫(kù)授權(quán)與自增序列操作實(shí)例代碼
- PostgreSQL有效地處理數(shù)據(jù)序列化和反序列化的方法
- PostgreSQL創(chuàng)建自增序列、查詢序列及使用序列代碼示例
- 解決postgresql 序列跳值的問(wèn)題
- Postgresql數(shù)據(jù)庫(kù)之創(chuàng)建和修改序列的操作
- PostgreSQL Sequence序列的使用詳解
- postgresql 中的序列nextval詳解
- PostgreSQL 序列增刪改案例
- postgresql重置序列起始值的操作
- postgresql 實(shí)現(xiàn)更新序列的起始值
相關(guān)文章
Postgresql常用函數(shù)及使用方法大全(看一篇就夠了)
使用函數(shù)可以極大的提高用戶對(duì)數(shù)據(jù)庫(kù)的管理效率,函數(shù)表示輸入?yún)?shù)表示一個(gè)具有特定關(guān)系的值,下面這篇文章主要給大家介紹了關(guān)于Postgresql常用函數(shù)及使用方法的相關(guān)資料,需要的朋友可以參考下2022-11-11
無(wú)公網(wǎng)IP環(huán)境下的PostgreSQL遠(yuǎn)程訪問(wèn)方案
本文提出了一種基于內(nèi)內(nèi)網(wǎng)穿透技術(shù)的PostPostQL遠(yuǎn)程訪問(wèn)解決方案,該方案無(wú)需公網(wǎng)IP,配置簡(jiǎn)單且安全性可控,支持?jǐn)U展性強(qiáng),通過(guò)三步實(shí)現(xiàn):隧道建立、端口映射和身份驗(yàn)證,實(shí)測(cè)延遲5-ms、帶寬NMbps,適用于開(kāi)發(fā)、數(shù)據(jù)查詢和報(bào)表導(dǎo)出場(chǎng)景,需要的朋友可以參考下2026-04-04
解決postgresql 數(shù)字轉(zhuǎn)換成字符串前面會(huì)多出一個(gè)空格的問(wèn)題
這篇文章主要介紹了解決postgresql 數(shù)字轉(zhuǎn)換成字符串前面會(huì)多出一個(gè)空格的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
PostgreSQL中GIN索引的三種使用場(chǎng)景
本文主要介紹了PostgreSQL中GIN索引的三種使用場(chǎng)景,包括數(shù)組類型、JSONB類型和全文搜索,具有一定的參考價(jià)值,感興趣的可以了解一下2025-07-07
SQLCipher數(shù)據(jù)遷移到PostgreSql詳細(xì)教程
這篇文章主要介紹了SQLCipher數(shù)據(jù)遷移到PostgreSql詳細(xì)教程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-09-09
PostgreSQL之分區(qū)表(partitioning)
通過(guò)合理的設(shè)計(jì),可以將選擇一定的規(guī)則,將大表切分多個(gè)不重不漏的子表,這就是傳說(shuō)中的partitioning。比如,我們可以按時(shí)間切分,每天一張子表,比如我們可以按照某其他字段分割,總之了就是化整為零,提高查詢的效能2016-11-11

