问题背景

、定时任务调用存储过程、将数据插入临时表时。出现了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$
BEGIN
  truncate 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.YZCD
    from (  
    SelectdistinctAJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
    from (select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
          from DB_DATA.RESULT_SELECT_QT
          where AJLBID = 1
          union all
          select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from DB_DATA.RESULT_SELECT_SF where AJLBID = 1
          union all
          select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from   DB_DATA.RESULT_SELECT_ZX where AJLBID = 1
          union all
          select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from   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.YZCD
    from (
    select distinct AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
  from (select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from   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重复的可能原因

  1. 服务器生成uuid太快、导致重复?

  2. 还是说在服务器正常但是真的同一时刻产生了重复的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$
BEGIN
  truncate 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,1
    from (  
    select distinct AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
      from
      (
      select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from   DB_DATA.RESULT_SELECT_QT where AJLBID = 1
          union all
          select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from   DB_DATA.RESULT_SELECT_SF where AJLBID = 1
          union all
          select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from   DB_DATA.RESULT_SELECT_ZX where AJLBID = 1
          union all
          select AJLBID,AJBSID,AJBS,AH,JBFYID,CBSPTID,CBRID,LARQ,JARQ,XGSJ,AJJZJDID,YZCD
            from   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 | 2
69d74a5ed31b8d51a59cf6d244cef763 | 2
(2 rows)
abase2=# select c_id,xh from DB_DATA.result_select_bak where c_id = '0cac29558223c7b3cd72f53116d62a2d';
              c_id               | xh
----------------------------------+----
0cac29558223c7b3cd72f53116d62a2d | 2
0cac29558223c7b3cd72f53116d62a2d | 1
(2 rows)
abase2=# select c_id,xh from DB_DATA.result_select_bak where c_id = '1ea8c12e58169105fa93ec1d838b6f07';
              c_id               | xh
----------------------------------+----
1ea8c12e58169105fa93ec1d838b6f07 | 9
1ea8c12e58169105fa93ec1d838b6f07 | 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。替换掉/opt/thunisoft/arterybase/3.5/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
$BODY
LANGUAGE '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重复引发血案的更多相关文章

  1. postgresql数据库中对重复数据的处理

    我们在使用postgresql数据库的时候,如果一张数据表在未做任何约束的情况下,很可能会出现几条完全一样的数据,即重复数据.如下图所示: 那么如果我们要删除其中的2条该怎么办呢?第一种我们可以清空表 ...

  2. PostgreSQL介绍以及如何开发框架中使用PostgreSQL数据库

    最近准备下PostgreSQL数据库开发的相关知识,本文把总结的PPT内容通过博客记录分享,本随笔的主要内容是介绍PostgreSQL数据库的基础信息,以及如何在我们的开发框架中使用PostgreSQ ...

  3. PostgreSQL数据库中获取表主键名称

    PostgreSQL数据库中获取表主键名称 一.如下表示,要获取teacher表的主键信息: select pg_constraint.conname as pk_name,pg_attribute. ...

  4. Windows 10 下 PostgreSQL 生成 UUID(Guid)

    最近在Windows 10 下安装了 PostgreSQL(postgresql-9.6.3-1-windows.exe),在学习过程中,发现PostgreSQL 支持UUID(Guid)类型,但是却 ...

  5. pg_restore - 从一个由 pg_dump 创建的备份文件中恢复 PostgreSQL 数据库。

    SYNOPSIS pg_restore [ option...] [ filename] DESCRIPTION 描述 pg_restore 是一种用于恢复由 pg_dump(1) 创建的任何非纯文本 ...

  6. pg_dump - 将一个PostgreSQL数据库抽出到一个脚本文件或者其它归档文件中

    SYNOPSIS pg_dump [ option...] [ dbname] DESCRIPTION 描述 pg_dump 是一个用于备份 PostgreSQL 数据库的工具.它甚至可以在数据库正在 ...

  7. MySQL&SQL server&Oracle&Access&PostgreSQL数据库sql注入详解

    判断数据库的类型 当我们通过一些测试,发现存在SQL注入之后,首先要做的就是判断数据库的类型. 常用的数据库有MySQL.Access.SQLServer.Oracle.PostgreSQL.虽然绝大 ...

  8. 阿里云IoT流转到postgresql数据库方案

    之前写过一篇如使用阿里云上部署.NET 3.1自定义运行时的文章,吐槽一下,虽然现在已经2022年了,但是阿里云函数计算的支持依然停留在.NET Core 2.1,更新缓慢,由于程序解包大小的限制,也 ...

  9. ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库

    前段时间在园子里看到了小蝶惊鸿 发布的有关绿色版的Linux.NET——“Jws.Mono”.由于我对.Net程序跑在Linux上非常感兴趣,自己也看了一些有关mono的资料,但是一直没有时间抽出时间 ...

随机推荐

  1. python list和函数之间的复制和原地址修改问题

    def change(a): a.pop() #自带的方法都是原地址修改 a=[,,] change(a) print (a)#直接修改了3. def change(a): a=[,,,] #复制操作 ...

  2. div 自适应宽度

    div 自适应宽度 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...

  3. 2018.10.23 NOIP模拟 行星通道计划(bit)

    传送门 卡常题. 成功卡掉了作死写树套树的zxy. 然而对我的二维bit无能为力. 直接维护两棵bit. bit1[i][j]bit1[i][j]bit1[i][j]表示左端点小于等于iii,右端点小 ...

  4. 2018.09.15[POI2008]BLO-Blockade(割点)

    描述 There are exactly nn towns in Byteotia. Some towns are connected by bidirectional roads. There ar ...

  5. 2018.09.05 bzoj1010: [HNOI2008]玩具装箱toy(斜率优化dp)

    传送门 一道经典的斜率优化dp. 推式子ing... 令f[i]表示装前i个玩具的最优代价. 然后用老套路. 我们只考虑把第j+1" role="presentation" ...

  6. foreach循环赋值问题

    foreach ($list as $key=>$val){ $data=array();//这一个一定要加上不然循环后,modify_one,modify_two都会赋值 if ($val[' ...

  7. JAVA“动态”为类添加属性

    部分参考:http://www.cnblogs.com/zy2009/p/6725843.html pom.xml中添加: <dependency> <groupId>comm ...

  8. SDK | 声波传输

    SDK | 声波传输 - 音频流生成 https://github.com/CloudSide/WaveTransSdk/tree/master/c/freq_util Objective-C: ht ...

  9. stdafx.h、stdafx.cpp是干什么用的?为什么我的每一个cpp文件都必须包含stdafx.h? Windows和MFC的include文件都非常大,即使有一个快速的处理程序,编

    sstdafx.h.stdafx.cpp是干什么用的?为什么我的每一个cpp文件都必须包含stdafx.h? Windows和MFC的include文件都非常大,即使有一个快速的处理程序,编译程序也要 ...

  10. Hbase和Hive的异同

    共同点:1.hbase与hive都是架构在hadoop之上的.都是用hadoop作为底层存储 区别:2.Hive是建立在Hadoop之上为了减少MapReduce jobs编写工作的批处理系统,HBa ...