postgresql数据库uuid重复引发血案
问题背景
、定时任务调用存储过程、将数据插入临时表时。出现了uuid重复的报错。
报错信息
[SQL]select DB_DATA.PR_SELECT() [Err] ERROR: duplicate key value violates unique constraint "pk_result_select" DETAIL: Key (c_id)=(3d0e61c6615092883cc5e29198aaffb7) already exists. CONTEXT: SQL statement "insert into DB_DATA.RESULT_SELECT(C_ID,AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD) select replace(cast(uuid_generate_v4() as varchar),'-','') as
排查问题
查看该函数
drop function "DB_DATA"."pr_select_bak"(); CREATE OR REPLACE FUNCTION "DB_DATA"."pr_select_bak"()RETURNS "pg_catalog"."void" AS $BODY$BEGINtruncate table DB_DATA.result_select_bak;insert into DB_DATA.result_select_bak(C_ID,AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD)select replace(cast(uuid_generate_v4() as varchar),'-','') as C_ID,T1.AJLBID,T1.AJBSID,T1.AJBS,T1.AH,T1.JBFYID,T1.CBSPTID,T1.CBRID,T1.LARQ,T1.JARQ,T1.XGSJ,T1.AJJZJDID,T1.YZCDfrom ( SelectdistinctAJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom (select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_QTwhere AJLBID = 1union allselect AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_SF where AJLBID = 1union allselect AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_ZX where AJLBID = 1union allselect AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_WS where AJLBID = 1) T2) T1; insert into DB_DATA.result_select_bak(C_ID,AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD)select replace(cast(uuid_generate_v4() as varchar),'-','') as C_ID,T1.AJLBID,T1.AJBSID,T1.AJBS,T1.AH,T1.JBFYID,T1.CBSPTID,T1.CBRID,T1.LARQ,T1.JARQ,T1.XGSJ,T1.AJJZJDID,T1.YZCDfrom (select distinct AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom (select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_QT where AJLBID = 2 --后面还有许多where条件不一样insert 的就不一一列举了......END $BODY$LANGUAGE 'plpgsql' VOLATILE COST 100; ALTER FUNCTION "DB_DATA"."pr_select_bak"() OWNER TO "atybase";
查看该存储过程并没有什么特别之处
观察uuid重复的规律
环境linux、数据库版本abase3.5.1、每次插入表总数:76824
调用15次存储过程操作查看uuid重复的条数:
无重复:3次
重复一条:5次
重复两条:4次
重复三条:2次
重复四条:1次
上网查了下uuid重复的概率:每秒产生10亿笔UUID,100年后只产生一次重复的机率是50%.如果地球上每个人都各有6亿笔UUID,发生一次重复的机率是50%
关于postgresql uuid重复的一片文章:连接当机器每微秒可以产生多个UUID时,在多个进程中有可能产生重复值。
原因就是前面对uuid.c的分析。因为本机唯一码必须确保同一个微秒内不能产生多个UUID,所以尽量不要并行产生。
猜测uuid重复的可能原因
服务器生成uuid太快、导致重复?
还是说在服务器正常但是真的同一时刻产生了重复的uuid。(这种情况就像被陨石击中一样、从实验结果的高命中可以基本排除)
疑问
这些重复的uuid是不同的insert生成的、还是一个insert里面就能生成重复的uuid?
为了解开疑问:首先将临时表result_select_bak去掉主键约束、添加一个序号(XH)字段用于记录是哪个insert插入的数据。
测试过程
DROP TABLE IF EXISTS "DB_DATA"."result_select_bak"; CREATE TABLE "DB_DATA"."result_select_bak" ( "c_id" varchar(35) COLLATE "default" NOT NULL, --中间字段不一一列举 "yzcd" int4, --添加序号 "xh" int4 ) WITH (OIDS=FALSE); CREATE OR REPLACE FUNCTION "DB_DATA"."pr_select_bak"()RETURNS "pg_catalog"."void" AS $BODY$BEGINtruncate table DB_DATA.result_select_bak;insert into DB_DATA.result_select_bak(C_ID,AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD,XH)select replace(cast(uuid_generate_v4() as varchar),'-','') as C_ID,T1.AJLBID,T1.AJBSID,T1.AJBS,T1.AH,T1.JBFYID,T1.CBSPTID,T1.CBRID,T1.LARQ,T1.JARQ,T1.XGSJ,T1.AJJZJDID,T1.YZCD,1from ( select distinct AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom (select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_QT where AJLBID = 1union allselect AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_SF where AJLBID = 1union allselect AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_ZX where AJLBID = 1union allselect AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCDfrom DB_DATA.RESULT_SELECT_WS where AJLBID = 1) T2) T1; insert into DB_DATA.result_select_bak(C_ID,AJLBID,AJBSID,AJBS,AH,JBFYID, CBSPTID,CBRID, LARQ,JARQ,XGSJ,AJJZJDID,YZCD,XH)select replace(cast(uuid_generate_v4() as varchar),'-','') as C_ID,T1.AJLBID,T1.AJBSID,T1.AJBS,T1.AH,T1.JBFYID,T1.CBSPTID,T1.CBRID,T1.LARQ,T1.JARQ,T1.XGSJ,T1.AJJZJDID,T1.YZCD,2.....END $BODY$LANGUAGE 'plpgsql' VOLATILE COST 100; ALTER FUNCTION "DB_DATA"."pr_select_bak"() OWNER TO "atybase";
测试结果
abase2=# select c_id from DB_DATA.result_select_bak group by c_id having count(*)>1;c_id ----------------------------------69d74a5ed31b8d51a59cf6d244cef763 (1 row) --相同序号、说明是一个insert里面产生了相同的uuid abase2=# select c_id,xh from DB_DATA.result_select_bak where c_id = '69d74a5ed31b8d51a59cf6d244cef763';c_id | xh ----------------------------------+----69d74a5ed31b8d51a59cf6d244cef763 | 269d74a5ed31b8d51a59cf6d244cef763 | 2 (2 rows) abase2=# select c_id,xh from DB_DATA.result_select_bak where c_id = '0cac29558223c7b3cd72f53116d62a2d';c_id | xh ----------------------------------+----0cac29558223c7b3cd72f53116d62a2d | 20cac29558223c7b3cd72f53116d62a2d | 1 (2 rows) abase2=# select c_id,xh from DB_DATA.result_select_bak where c_id = '1ea8c12e58169105fa93ec1d838b6f07';c_id | xh ----------------------------------+----1ea8c12e58169105fa93ec1d838b6f07 | 91ea8c12e58169105fa93ec1d838b6f07 | 1 (2 rows) ...
经测试发现不管是同一个insert还是不同的insert都有可能生成相同的uuid。
到这一步我开始怀疑是不是服务器有问题了。但是这种小概率事件真的就发生在我身上了吗?我还是不太相信小概率事件会发生
转换角度
想到默认abase安装扩展会有三个uuid函数:uuid_generate_v1()、uuid_generate_v4()、uuid_generate_v1mc()。所以考虑使用select uuid_generate_v1();替换掉uuid_generate_v4()看结果如何。但是报错找不到该函数。
开始怀疑
是不是插件的问题呢?
将abase3.5.1自带的uuid插件uuid-ossp.so。替换掉../lib/postgresql/uuid-ossp.so、然后重启数据库。在DB_DATA下面创建扩展函数:create extension “uuid_ossp”
再次测试
执行最开始的存储过程没有发现重复uuid、多测试了几次还是没有、这个时候感觉找到问题所在了应该就是插件的问题。
为了验证正确性然后测试修改后添加了序号的存储过程发现还是有重复的数据。开始纳闷了! 详细对比这两函数获取uuid的方式: 正常获取、uuid:replace(cast(uuid_generate_v4() as varchar,’-’,’’)) 异常获取、uuid:replace(public.uuid_generate_v4():text,’-’,’’) 正常获取:不加schema默认获取当前DB_DATA下面的uuid_generate_v4()函数。 异常获取:获取了public下面的uuid_generate_v4();
查看public下面的函数
CREATE OR REPLACE FUNCTION "public"."uuid_generate_v4()"RETURNS "pg_catalog"."varchar" AS $BODY$BEGIN--Routne body goes here...RETURN md5(random()::text || now::text); END $BODYLANGUAGE 'plpgsql' VOLATILE COST 100; ALTER FUNCTION "public"."uuid_generate_v4"() OWNER TO "atybase";
对比自带uuid函数
CREATE OR REPLACE FUNCTION "public"."uuid_generate_v4"()RETURNS "pg_catalog"."uuid" AS '$libdir/uuid-ossp', 'uuid_generate_v4'LANGUAGE 'c' VOLATILE STRICT COST 1; ALTER FUNCTION "public"."uuid_generate_v4"() OWNER TO "sa";
发现问题
观察可以看到该函数被重新定义了、没有使用基础动态链接库、而是使用了随机数和当前时间组合md5加密的方式、导致uuid重复。
结语
在安装abase3.5.1以上版本时默认会再public下面创建uuid函数、直接调用即可、不需要再去手动创建。如果在脚本中使用了set search_path to db_xxx;然后去调用uuid_generate_v4(),会报错找不到该函数、可以使用set search_path to public,db_xxx;同时指定多个schema。
postgresql数据库uuid重复引发血案相关推荐
- postgresql数据库中使用使用UUID
目录 问题现象: 问题分析: 解决方法: 问题现象: 今天在项目学习中,需要给数据添加一个id,组长要求使用UUID. 问题分析: 由于我们的项目中使用的是postgresql数据库,那么如果在pos ...
- Debezium系列之:使用Debezium接入PostgreSQL数据库数据到Kafka集群的详细技术文档
Debezium系列之:使用Debezium接入PostgreSQL数据库数据到Kafka集群的详细技术文档 一.概述 二.连接器的工作原理 1.安全 2.快照 3.Ad hoc snapshots ...
- 使用PostgREST的RestAPI操作PostgreSQL数据库教程
使用PostgREST的RestAPI操作PostgreSQL数据库教程 表和视图 公开的架构中的所有视图和表均可被查询的活动数据库角色访问,并且可供活动数据库角色访问.它们暴露在一级深度路线中.例如 ...
- 详解PostgreSQL数据库中的两阶段锁
点击上方"蓝字" 关注我们,享更多干货! 数据库中的对象是共享的,假如不同的用户同时修改某个对象,就会出现数据错乱,从而破坏数据库的数据一致性,违反事务的隔离性原则. 为了满足隔离 ...
- PostgreSQL中UUID的完整指南
目录 理解SQL中的键 自然键与代理键 使用PostgreSQL创建主键的语法 创建复合主键 通用唯一ID?UUID介绍 UUID_v4与UUID_V1 使用uuid-osp创建UUID主键-Post ...
- pg安装部署linux_Linux下postgresql数据库部署与配置
1.检查postgresql是否已经安装:rpm -qa | grep postgres 2.检查PostgreSQL 安装位置:rpm -qal | grep postgres 3.卸载Postgr ...
- Debezium系列之:Debezium2.X之PostgreSQL数据库的Debezium连接器
Debezium系列之:Debezium2.X之PostgreSQL数据库的Debezium连接器 一.概述 二.连接器的工作原理 1.安全 2.快照 3.临时快照 4.触发临时快照 5.增量快照 6 ...
- postgresql 数据库操作点记
postgresql 数据库操作点记 普通查询 查询结果拼接 查询所有字段 排除某些字段 处理时间 查询结果去除null值 安装扩展 自动填充uuid 数据库插入guid函数 清空表格数据 分组查询的 ...
- 数据库服务器 之 PostgreSQL数据库的日常维护工作
来自:LinuxSir.Org 摘要:为了保持所安装的 PostgreSQL 服务器平稳运行, 我们必须做一些日常性的维护工作.我们在这里讨论的这些工作都是经常重复的事情, 可以很容易地使用标准的 U ...
最新文章
- 《CCNP TSHOOT 300-135认证考试指南》——2.2节故障检测与排除及网络维护工具箱
- 设计模式(0)简单工厂模式
- 取一个字符串中的数字
- 推荐“公主妄想症系列之二:第一次”
- HDU 1284 钱币兑换问题 (动态规划 背包方案数)
- 结婚生娃和去核电站参观,哪个更安全?
- R语言聚类算法之密度聚类(Density-based Methods)
- 医疗AI市场三年内规模可达66亿美元,哪些应用最有潜力?| 报告
- 比赛 | 第一届古汉语分词与词性标注国际评测来啦
- 手机java版怎么换皮肤_手机QQ皮肤更换方法(安卓版)
- 地理信息安全在线培训考试系统题库-多选题
- 单纯形法算法实现--java版
- TrafficMonitor 网速监控悬浮窗软件
- Python绘图实例35:漫天雪花绘制
- CF1680F Lenient Vertex Cover题解
- FTP服务器搭建报错Warning: FTP over TLS is not enabled, users cannot securely log in.
- 6到飞起, 360儿童手表三款新品即将发布
- 二面深信服前端,秋招面经分享
- php__file__用法,PHP 的常量__FILE__的用法图解
- 发明计算机作文300字,关于科学发明的作文300字(共7篇)