之前帮客户处理食堂系统问题时,细想发现了一个问题。
系统中,卡号和员工号是多对多的关系,card_info表和sales表之间,是由一个XXXX-XXXX-XXXX-XXXX格式的随机数序列作为主键的,客户删除card_info表后,重新生成了一张card_info表,这就导致sales中的一部分数据被清空。
但是发生了一件like a miracle的事,新生成的card_info中的7行数据,能够匹配到sales中数据行,堪比泰坦尼克号撞了100000座冰山还没沉,堪称奇迹中的奇迹,这也是一开始客户觉得删除card_info表并没有什么不妥,以至于在删除后5天,财务需要核对数据时,才发现问题,还有数据备份等一系列问题。
客户用的是Microsoft的SQLServer,我用的不多,开发使用的随机数代码我也不知道,除非客户再次遇到问题,不然我再摸到他们系统的概率就为0。不说这个,我们现在就来探究下oracle数据库的随机数,是否也会发生这样的撞车事故。
1.准备环境
创建一张表,用来存放随机数
CREATE TABLE RANDOM_T (ID VARCHAR2(50) NOT NULL);
插入数据,先来100001个吧
BEGIN
FOR I IN 1..10001 LOOP
INSERT INTO RANDOM_T (ID) SELECT UPPER(REPLACE(TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x'),' ',''))||'-'||UPPER(REPLACE(TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x'),' ',''))||'-'||UPPER(REPLACE(TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x'),' ',''))||'-'||UPPER(REPLACE(TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x')||TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(0,15)),'x'),' ','')) FROM DUAL;
COMMIT;
END LOOP;
END;
/
2.验证下数据
完美,我们现在有10001条数据,我们再来看下是否有重复
完美,没有重复。
3.暴力测试下
区区10001条数据,肯定是不能测出问题的,暴力测试下,我们先来1000000条:
经过漫长的等待,终于好了,再来验证下:
还是非常完美,没有重复,看来ORACLE的随机数,还是比较随机的,看来下次得装个SQLServer来测试下,card_info总共才7000多条数据,竟然还能有7条匹配上,很是奇妙。
4.无聊一下
之前的测试,重复概率是很低的,毕竟是36的16次方分之一,如果我们降低一点要求,36的4次方分之一概率,会有多少重复的呢?
重新生成下随机数:
36的4次方,1679616,如果没有重复,那,就真的,又一次出现了,奇迹。
见证奇迹的时刻:
果然没有让我失望啊,重复率是100%
看了一下总共生成50625条不同的数据:
才占1679616的3%。
我来重新生成一下1679616条数据,来看看唯一率是否还是3%。
再次生成随机数,计算出来唯一率还是只有3%。
5.胡说八道
关于这个随机数列,我还是喜欢加点数据本身的东西进去,比方说日期,或者数据本身的编号,这样在加上随机数,会比较保险。就像壹原侑子说的“这个世界上没有什么偶然,有的只是必然。”不要心存侥幸,少年!
领取专属 10元无门槛券
私享最新 技术干货