PostgreSQL中int類型達到上限的一些處理方案

使用int類型作為表的主鍵在pg中是很常見的情況,但是pg中int類型的范圍在-2147483648到2147483647,最大只有21億,這個在一些大表中很容易就會達到上限。一旦達到上限,那么表中便沒辦法在插入數據了,這個將會是很嚴重的問題。

如何監控?

對于此類情況,我們可以考慮將序列使用情況加入到監控中,防止達到最大值后表中無法插入數據的情況發生。

可以使用下面SQL去查詢庫中序列的使用情況:

SELECTseqs.relname AS sequence,format_type(s.seqtypid, NULL) sequence_datatype,CONCAT(tbls.relname, '.', attrs.attname) AS owned_by,format_type(attrs.atttypid, atttypmod) AS column_datatype,pg_sequence_last_value(seqs.oid::regclass) AS last_sequence_value,TO_CHAR((CASE WHEN format_type(s.seqtypid, NULL) = 'smallint' THEN(pg_sequence_last_value(seqs.relname::regclass) / 32767::float)WHEN format_type(s.seqtypid, NULL) = 'integer' THEN(pg_sequence_last_value(seqs.relname::regclass) / 2147483647::float)WHEN format_type(s.seqtypid, NULL) = 'bigint' THEN(pg_sequence_last_value(seqs.relname::regclass) / 9223372036854775807::float)END) * 100, 'fm9999999999999999999990D00%') AS sequence_percent,TO_CHAR((CASE WHEN format_type(attrs.atttypid, NULL) = 'smallint' THEN(pg_sequence_last_value(seqs.relname::regclass) / 32767::float)WHEN format_type(attrs.atttypid, NULL) = 'integer' THEN(pg_sequence_last_value(seqs.relname::regclass) / 2147483647::float)WHEN format_type(attrs.atttypid, NULL) = 'bigint' THEN(pg_sequence_last_value(seqs.relname::regclass) / 9223372036854775807::float)END) * 100, 'fm9999999999999999999990D00%') AS column_percent
FROMpg_depend dJOIN pg_class AS seqs ON seqs.relkind = 'S'AND seqs.oid = d.objidJOIN pg_class AS tbls ON tbls.relkind = 'r'AND tbls.oid = d.refobjidJOIN pg_attribute AS attrs ON attrs.attrelid = d.refobjidAND attrs.attnum = d.refobjsubidJOIN pg_sequence s ON s.seqrelid = seqs.oid
WHEREd.deptype = 'a'AND d.classid = 1259;

查詢出的結果類似這樣:

解決方案

1、修改序列為負數

因為pg中int類型是包含負數的,所以如果序列從0開始遞增即將達到最大值,那么可以考慮切換到負數排序。將序列的起始值設置為-1然后降序來遞增。

alter sequence test_id_seq no minvalue start with -1 increment -1 restart;

這種方式不需要修改表的結構,可以很快的解決問題。但是這種方案的前提是主鍵列只是單純用來做遞增的唯一約束用的,可以接受使用負數才行。

而且這也只能將可用數據范圍翻倍,只能短期解決問題,如果后續負數用完了那就沒辦法了,只能去修改字段類型了。

2、修改序列cycle屬性(分區表)

如果你的表是分區表的話,還可以考慮直接修改序列的屬性為cycle。因為在pg中,主鍵并不是全局性的約束,而只是針對單個分區的。

即分區1和分區2中都可以出現主鍵id相同的數據。當然,這種方案僅限于分區表的場景。

alter sequence test_id_seq cycle;

3、修改字段類型為bigint

如果上面倆種方案都沒法解決的話,那最終只能選擇修改字段類型為bigint的方式了。不過肯定也不能直接去這樣修改:

alter table xxx alter id type bigint;

畢竟一般int類型達到上限的表都很大了,修改int為bigint是會重寫表的,需要長時間持有獨占鎖,這個對業務來說是難以接受的。

比較推薦的方案就是新增一個bigint列,然后用其去替換原先的int列。

alter table test add column id_new bigint;
CREATE UNIQUE INDEX CONCURRENTLY test_id_new ON test (id_new);

緊接著再創建對應的bigint的序列。

CREATE SEQUENCE test_id_new_seq START 2147483776 AS bigint;
ALTER TABLE test ALTER COLUMN id_new SET DEFAULT nextval ('test_id_new_seq');
alter sequence test_id_new_seq owned by test.id_new;

現在舊的int類型和新的bigint類型的列就都在自增了。

bill=# select * from test;id     | value |   id_new
------------+-------+------------2000000009 |       |2000000010 |       |2000000011 |       | 21474837762000000012 |       | 2147483777

然后我們就可以將id列和id_new列進行重命名了,這一步需要放在同一個事務中去處理。

BEGIN;
ALTER TABLE test DROP CONSTRAINT test_pkey;
ALTER TABLE test ALTER COLUMN id DROP DEFAULT;
ALTER TABLE test RENAME COLUMN id TO id_old;
ALTER TABLE test RENAME COLUMN id_new TO id;
ALTER TABLE test ALTER COLUMN id_old DROP NOT NULL;
ALTER TABLE test ADD CONSTRAINT id_not_null CHECK (id IS NOT NULL) NOT VALID;
COMMIT;

由于之前添加id_new列中有大量null值,因此需要將約束設置為NOT VALID,但是我們需要將該列變為主鍵的話,之前的null值還是需要去處理的,這里使用批量update的方式去進行更新。

WITH unset_values AS (SELECTid_oldFROMtestWHEREid IS NULLLIMIT 1000)
UPDATEtest
SETid = unset_values.id_old
FROMunset_values
WHEREunset_values.id_old = test.id_old;

null的數據處理完之后,我們便可以將新的id列更改為主鍵了。

ALTER TABLE test VALIDATE CONSTRAINT id_not_null;
ALTER TABLE test ADD CONSTRAINT test_pkey PRIMARY KEY USING INDEX test_id_new;
ALTER TABLE test DROP CONSTRAINT id_not_null;

最后我們便可以將舊的id列刪除了,記得刪除完之后重新收集下表的統計信息。

bill=# ALTER table test drop column id_old;
ALTER TABLE
bill=# analyze t1;
ANALYZE
bill=# \d testTable "public.test"Column |  Type   | Collation | Nullable |               Default
--------+---------+-----------+----------+--------------------------------------value  | integer |           |          |id     | bigint  |           | not null | nextval('test_id_new_seq'::regclass)
Indexes:"test_pkey" PRIMARY KEY, btree (id)

總的來說這種方式也是比較麻煩的,其中在線創建索引和批量update都是比較耗時的操作。

因此對于應用來說還是應該盡可能的避免出現這種情況,大表在設計的階段就應該考慮使用bigint或者bigserial來代替int類型,不要在int類型快要達到最大值再開始去救火。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/714391.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/714391.shtml
英文地址,請注明出處:http://en.pswp.cn/news/714391.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【react native】css踩坑記錄

1、IOS上面opacity重疊失效 在 iOS 上,當兩個具有相同背景色的元素重疊時,不透明度(opacity)較低的元素會顯示在較高的元素上方。 所以考慮使用rgba的形式。 // 對于下面這種寫法,如果存在container和activeIndicat…

word文檔空格不能有下劃線【筆記】

word文檔空格不能有下劃線 2024-3-1 21:20:24 推薦 word下劃線打不出來了,是怎么回事? 問題 字后面打不出來下劃線 操作 1.點擊文件 左上角,點擊“文件”。 2.點擊選項 鼠標下滑,點擊“選項”。 3.點擊常規與保存 點擊“…

java基礎-mysql

文章目錄 mysql基礎面試題什么是mysql什么是事務并發事務帶來的影響事物的隔離級別索引大表優化什么是池化思想,什么是數據庫連接池,為什么要用數據庫連接池?鎖,表鎖;樂觀鎖,悲觀鎖MySQL主備同步的基本原理SQL什么情況…

[⑥5G NR]: 無線接口協議,信道映射學習

5G系統整體包括核心網、接入網以及終端部分,接入網與終端間通過無線空口協議棧進行連接。無線接口可分為三個協議層:物理層(L1)、數據鏈路層(L2)和網絡層(L3)。 L1:物理…

【python】json轉成成yaml中文編碼異常顯示成:\u5317\u4EAC\u8DEF123\u53F7

姊妹篇:【python】json轉成成yaml json數據 {"name": "張三","age": 30,"isMarried": false,"children": [{"name": "小王","age": 5},{"name": "小李",&qu…

mysql冷備

數據庫備份類型 冷備份:在數據庫停止服務的情況下進行備份 熱備份:在數據庫處于運行狀態下進行備份 溫備份:不可寫但可讀的情況下進行備份 冷備分時,只需要在停止數據庫后,拷貝數據目錄到另一個地方即可。 mysql 啟…

為什么不能啟動游戲錯誤代碼126 加載bugreportnew.dll失敗

錯誤代碼126通常表示在嘗試加載某個動態鏈接庫(DLL)文件時出現了問題。在您提到的例子中,bugreportnew.dll 文件未能成功加載,這可能是由于以下幾個原因: 騰訊云2024新春采購節優惠活動入口:https://curl.q…

Linux---進程信號

一、信號的概念 信號是一種向目標進程發送通知消息的機制 信號的特性(可以結合紅綠燈、防空警報等生活樣例來理解) 1、在信號沒有出現之前,我們就已經知道如何去處理信號,即我們認識信號 2、信號是異步產生的,即我們不知道它具體何時產生 3、…

基于MQTT協議實現微服務架構事件總線

一、場景描述 昨天在博客《客戶端訂閱服務端事件的實現方法》中提出了利用websocket、服務端EventEmitter和客戶端mitt實現客戶端訂閱服務端事件,大大簡化了客戶端對服務端數據實時響應的邏輯。上述方案適用于單服務節點的情形。 對于由服務集群支撐的微服務架構&…

Redis 之七:穿透、擊穿、雪崩

(本內容部分來自知乎網等網絡) Redis 緩存的使用,極大的提升了應用程序的性能和效率,特別是數據查詢方面。但同時,它也帶來了一些問題。其中,最要害的問題,就是數據的一致性問題,從嚴…

Educational Codeforces Round 132 (Rated for Div. 2) E. XOR Tree(啟發式合并+貪心)

題目 n(n<2e5)個點的樹&#xff0c;點i權值ai&#xff08;1<ai<2^30&#xff09; 修改最少的點的權值&#xff0c;使得樹上不存在異或和為0的簡單路徑&#xff0c;輸出最少的點數 權值可以被修改成任意正整數&#xff08;可以是無限大&#xff09; 思路來源 官方…

【leetcode】環形鏈表?環形鏈表II

大家好&#xff0c;我是蘇貝&#xff0c;本篇博客帶大家刷題&#xff0c;如果你覺得我寫的還不錯的話&#xff0c;可以給我一個贊&#x1f44d;嗎&#xff0c;感謝?? 目錄 1.環形鏈表解題拓展&#xff1a; 2.環形鏈表II 1.環形鏈表 點擊查看題目 解題 思路: bool hasCycle…

【算法集訓】基礎算法:基礎排序 - 插入排序

一、基本理解 插入排序(nsertion Sort)&#xff0c;一般也被稱為直接插入排序&#xff0c;是一種簡單直觀的排序算法。 **工作原理&#xff1a;**將待排列元素劃分為「已排序」和「未排序」兩部分&#xff0c;每次從「未排序的」元素中選 擇一個插入到「已排序的」元素中的正確…

劍指offer58—II 左旋轉字符串 c++

題目 字符串的左旋轉操作是把字符串前面的若干個字符轉移到字符串的尾部。請定義一個函數實現字符串左旋轉操作的功能。比如,輸入字符串"abcdefg"和數字2,該函數將返回左旋轉兩位得到的結果"cdefgab"。 示例 1: 輸入: s = “abcdefg”, k = 2 輸出: “…

MySQL 多表查詢 連接查詢 內連接

介紹 內連接查詢是兩張表中交集的部分 連接模式 隱式內連接 SELECT 字段列表 FROM 表1,表2 WHERE 條件顯式內連接 SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 連接條件案例 有兩張表一個表為學生表&#xff0c;另一個表為班級表&#xff0c;現在需要查詢學生時候在查…

接口測試(全)

&#x1f345; 視頻學習&#xff1a;文末有免費的配套視頻可觀看 &#x1f345; 關注公眾號【互聯網雜貨鋪】&#xff0c;回復 1 &#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 大多數人對于接口測試都覺得是一種高大上的測試&#xff0c;覺得…

羊大師分析,羊奶粉適合什么樣的人群喝

羊大師分析&#xff0c;羊奶粉適合什么樣的人群喝 羊奶粉適合多種人群食用&#xff0c;包括兒童、老年人、孕婦以及身體虛弱或處于疾病康復期的人群。 對于兒童來說&#xff0c;羊奶粉是一種很好的營養品。它含有豐富的蛋白質、脂肪、礦物質和維生素&#xff0c;能夠滿足兒童…

【前端素材】推薦優質后臺管理系統網頁Star admin平臺模板(附源碼)

一、需求分析 1、系統定義 后臺管理系統是一種用于管理和控制網站、應用程序或系統的管理界面。它通常被設計用來讓網站或應用程序的管理員或運營人員管理內容、用戶、數據以及其他相關功能。后臺管理系統是一種用于管理網站、應用程序或系統的工具&#xff0c;通常由管理員使…

三種圖片預覽插件viewer、vue-photo-preview、vue-picture-preview

第一種&#xff1a;viewerjs使用介紹 1、先安裝依賴 npm install v-viewer --save2、main.js內引用并注冊調用 //main.js import Viewer from ‘v-viewer’ import ‘viewerjs/dist/viewer.css’ Vue.use(Viewer); Viewer.setDefaults({ Options: { “inline”: true, “butt…

王志亮出席海爾智慧樓宇發酵行業的低碳節能解決方案

演講嘉賓&#xff1a;王志亮 食品醫藥用戶群總監 青島海爾空調電子有限公司 演講題目&#xff1a;海爾智慧樓宇在發酵行業的低碳、節能解決方案 會議簡介 “十四五”規劃中提出&#xff0c;提高工業、能源領城智能化與信息化融合&#xff0c;明確“低碳經濟”新的戰略目標&…