问题背景

、定时任务调用存储过程、将数据插入临时表时。出现了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. webapp的优化总结

    1. 最先加载本地数据,下拉刷新再取最新数据. 2. 图片延后加载.一种方法先<div data-url="xx.png"></div>,先加载一个div, ...

  2. Warning: Attempt to present A on B whose view is not in the window hierarchy!

    昨天写豆瓣发广播Demo的时候,为了写Demo的简单,就使用了Storyboard,结果执行视图跳转时遇到了这个问题: Warning: Attempt to present <UINaviga ...

  3. CentOS yum 源的配置与使用(引用)

    http://www.cnblogs.com/mchina/archive/2013/01/04/2842275.html

  4. Spring中property-placeholder的使用与解析

    Spring中property-placeholder的使用与解析 我们在基于spring开发应用的时候,一般都会将数据库的配置放置在properties文件中. 代码分析的时候,涉及的知识点概要: ...

  5. day15(mysql 的多表查询,事务)

    mysql之多表查询 1.合并结果集 作用:合并结果集就是把两个select语句查询的结果连接到一起! /*创建表t1*/ CREATE TABLE t1( a INT PRIMARY KEY , b ...

  6. CGA填充算法之种子填充算法

    CGA填充算法之种子填充算法 平面区域填充算法是计算机图形学领域的一个很重要的算法,区域填充即给出一个区域的边界 (也可以是没有边界,只是给出指定颜色),要求将边界范围内的所有象素单元都修改成指定的颜 ...

  7. Androd Studio测试

    测试的分类: 在软件开发领域,程序员开发编码后,需要测试部门的测试,才可以发布软件版本,所以对测试的概念需要了解: 黑盒测试:我的理解是,黑盒测试更多的是体力活,按照测试用例,在屏幕上不停的操作的方式 ...

  8. 用C#开发的双色球走势图(原创)值得园友拥有

    首先声明,个人纯粹无聊之作,不作商业用途. 我相信每个人都拥有一个梦想那就是有朝一日能中500W,这个也一直是我的梦想,并默默每一期双色球或多或少要贡献自己一点点力量,本人并不属于那种铁杆的彩票迷,每 ...

  9. linux系统编程之文件与IO(七):时间函数小结

    从系统时钟获取时间方式 time函数介绍: 1.函数名称: localtime 2.函数名称: asctime 3.函数名称: ctime 4.函数名称: difftime 5.函数名称: gmtim ...

  10. OC 数组以及字符串拼接与分割

    //@""空的字符串对象-------分割 NSString * ptr = @"I am a man"; NSArray * array = [ptr com ...