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.mzph.cn/news/714391.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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…

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…

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;通常由管理员使…

黑马JUC笔记

黑马JUC笔记 1.概览 2.进程与线程 2.1 进程与线程 进程 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至 CPU&#xff0c;数据加载至内存。在 指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管…

Cisco Secure ACS 5.8.0.32 安装 + Crack 教程

Cisco Secure ACS 5.8.0.32 安装 Crack 教程 前言系统环境开始安装 开始破解导入授权文件 前言 在ESXi 6.7 上经历过无数次的安装尝试 测试了各种兼容版本都没有安装成功,记最后一次安装成功的过程. 系统环境 服务器 : Dell R720xd CPU : E5-2620 v2 系统 : ESXi 6.7…

简单控件属性设置

1、设置文本的内容 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"…

十四、Qt主机信息与网络编程

一、主机信息 1、主机信息接口 QHostInfo&#xff1a;获取主机名称和IP地址QNetWorkInterface&#xff1a;获取主机的所有网络接口&#xff0c;包括子网掩码和广播地址等 &#xff08;1&#xff09;使用 项目添加模块QT network2、实现程序 &#xff08;1&#xff0…

【01】openEuler 源码安装 PostgreSQL

openEuler 源码安装 PostgreSQL 部署环境说明Shell 前端软件包管理器基础概念YUM 简介DNF 简介 源码安装 PostgreSQL环境变量&#xff08;env&#xff09;设置临时环境变量设置永久环境变量设置 初始化数据库&#xff08;initdb&#xff09; 数据库基本操作数据库基本配置&…

c++结构体内存对齐

结构体内存对齐 试试运行下面的例子 #include <stdio.h> #include <stdlib.h>using namespace std;struct A{char c;int i; };struct B{char c; int i; double d; };struct C{char c;int i;double d;char c1; };int main(){printf("sizeof(A): %d\n"…

SparkStreaming在实时处理的两个场景示例

简介 Spark Streaming是Apache Spark生态系统中的一个组件&#xff0c;用于实时流式数据处理。它提供了类似于Spark的API&#xff0c;使开发者可以使用相似的编程模型来处理实时数据流。 Spark Streaming的工作原理是将连续的数据流划分成小的批次&#xff0c;并将每个批次作…