[PLSQL]Are you sure it will be definitely random? (DBMS_RANDOM.SEED)
2010-10-27 20:46
399 查看
如果想得到一个随机值,非常自然地会想到用DBMS_RANDOM包来做。但是有时候不注意,可能得到的并不是我们想要的结果,就遇到如下一个”陷阱“:
假设有张表T里面有一列存储字符串,并且在这个列上有个unique constraint, 由于系统并不care这列里面存储的字符串是啥东东,只要它是唯一的就OK。那么有一个简单的function来获取每次需要往这一列插入的字符串,如下所示:
因为同样的SEED会产生同样的随机值,自然是想确保每次调用的时候都是用不同的seed来生成随机的字符串,时间(time)自然是很常见的SEED选择。 一般来说, GET_NEXT_STR可以工作的很好,没有一点问题。
但是,如果在一个循环里面去调用这个function,或者多线程同时来调用这个function, 很可能就会出现让人”惊讶"的情况。可以进行如下简单地测试...
输出结果如下:
可以看到结果出现了很多重复的值,居然不是绝对随机的!What a surprise! 不过细细想想,用时间作为seed能够保证每次调用的时候seed的值都是唯一的吗?
SELECT TO_CHAR(SYSTIMESTAMP, 'ddmmyyyyHH24MMSSFF') INTO V_SEED FROM DUAL;
常规调用的话,每次返回的值确实不一样,但是因为是放在一个循环里面来执行,CPU运行速度快过我们能捕获到时间的变化,因此有些调用的seed值会一样的,可以简单测试如下,
输入结果如下,
因此,这样常规地用timestamp来做seed不能保证特殊情况下的需求。那么该如何做呢,一种方法很简单,就是每次调用的时候,我让当前线程sleep一下下,这样可以保证每次循环得到的seed都不同,当然缺点也显而易见,响应时间会受影响。另外一种方法,我觉得可以之间不要自己来生成seed, 而是让系统自动为我们生成,这样生成重复的值的可能性会小得多!
【Sum-up】
以后再”随机“的时候,可要小心点了:)
假设有张表T里面有一列存储字符串,并且在这个列上有个unique constraint, 由于系统并不care这列里面存储的字符串是啥东东,只要它是唯一的就OK。那么有一个简单的function来获取每次需要往这一列插入的字符串,如下所示:
CREATE OR REPLACE FUNCTION GET_NEXT_STR RETURN VARCHAR2 IS V_SEED VARCHAR2(50); BEGIN SELECT TO_CHAR(SYSTIMESTAMP, 'ddmmyyyyHH24MMSSFF') INTO V_SEED FROM DUAL; DBMS_RANDOM.SEED(V_SEED); RETURN DBMS_RANDOM.STRING('A', 20); END GET_NEXT_STR;
因为同样的SEED会产生同样的随机值,自然是想确保每次调用的时候都是用不同的seed来生成随机的字符串,时间(time)自然是很常见的SEED选择。 一般来说, GET_NEXT_STR可以工作的很好,没有一点问题。
但是,如果在一个循环里面去调用这个function,或者多线程同时来调用这个function, 很可能就会出现让人”惊讶"的情况。可以进行如下简单地测试...
set serveroutput on BEGIN FOR I IN 1..10 LOOP DBMS_OUTPUT.PUT_LINE(GET_NEXT_STR); END LOOP; END;
输出结果如下:
AwPUykNKErDexsElUnwC snKBvcxsTUiMSLWuMCgo snKBvcxsTUiMSLWuMCgo snKBvcxsTUiMSLWuMCgo snKBvcxsTUiMSLWuMCgo snKBvcxsTUiMSLWuMCgo zNuLksgAvpBiSqXGqCeA zNuLksgAvpBiSqXGqCeA zNuLksgAvpBiSqXGqCeA zNuLksgAvpBiSqXGqCeA
可以看到结果出现了很多重复的值,居然不是绝对随机的!What a surprise! 不过细细想想,用时间作为seed能够保证每次调用的时候seed的值都是唯一的吗?
SELECT TO_CHAR(SYSTIMESTAMP, 'ddmmyyyyHH24MMSSFF') INTO V_SEED FROM DUAL;
常规调用的话,每次返回的值确实不一样,但是因为是放在一个循环里面来执行,CPU运行速度快过我们能捕获到时间的变化,因此有些调用的seed值会一样的,可以简单测试如下,
set serveroutput on BEGIN FOR I IN 1..10 LOOP DBMS_RANDOM.SEED(TO_CHAR(SYSTIMESTAMP, 'ddmmyyyyHH24MMSSFF')); DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSTIMESTAMP, 'ddmmyyyyHH24MMSSFF') || '---' || DBMS_RANDOM.STRING('A', 20)); END LOOP; END;
输入结果如下,
27102010201031970000000---pULExiNuvqHCEwdQWnZQ 27102010201031980000000---pULExiNuvqHCEwdQWnZQ 27102010201031980000000---yIsbzOzTCSvcJxmXPEzG 27102010201031980000000---yIsbzOzTCSvcJxmXPEzG 27102010201031980000000---yIsbzOzTCSvcJxmXPEzG 27102010201031980000000---yIsbzOzTCSvcJxmXPEzG 27102010201031990000000---yIsbzOzTCSvcJxmXPEzG 27102010201031990000000---uySDJCwCmPqYrpJeKMeY 27102010201031990000000---uySDJCwCmPqYrpJeKMeY 27102010201031990000000---uySDJCwCmPqYrpJeKMeY
因此,这样常规地用timestamp来做seed不能保证特殊情况下的需求。那么该如何做呢,一种方法很简单,就是每次调用的时候,我让当前线程sleep一下下,这样可以保证每次循环得到的seed都不同,当然缺点也显而易见,响应时间会受影响。另外一种方法,我觉得可以之间不要自己来生成seed, 而是让系统自动为我们生成,这样生成重复的值的可能性会小得多!
【Sum-up】
以后再”随机“的时候,可要小心点了:)
相关文章推荐
- It is said that wars in the 21st century will be fought over water. Do you agree? What do you think can be done now to alleviate
- The authenticity of host 'www.101du.net (60.210.17.34)' can't be established. RSA key fingerprint is xxxx. Are you sure you want
- I’m Sure It Will Only Take You A Few Days To Code
- I’m Sure It Will Only Take You A Few Days To Code
- 准备踏入IT编程的学子们,你们第一门编程语言选谁? Are You Ready? Go!
- The file “xxx” couldn’t be opened because you don’t have permission to view it.
- HDOJ2270(How Many Friends Will Be Together With You)
- The file “XXX” couldn’t be opened because you don’t have permission to view it.
- 如果你的软件事关重大,你就会用C++编写它(If your software matters, you will write it in C++)
- 取消弹出信息:Are you sure you want to continue connecting
- Android: You are not using bash - builds will fail
- 在Design界面直接拖放控件的时候,提示AS- This view is not constrained vertically. At runtime it will jump to the left/(0,0) unless you
- Friends主题曲 I will be there for you
- Make sure you have Java JDK or JRE installed and the required ports are free
- 程序员之殇 —— (Are you afraid of me? Don't be.)灵感=神秘感
- Follow your heart, always remember who you are, what you want to be.
- The object of type 'RectTransform' has been destroyed but you are still trying to access it
- Where Will the IT Jobs Be in 2010?
- "Android SDK and AVD Manager" cannot be made visible because all of its children are in unavailable
- Could not extract package's data directory. Are you sure that your installed application is debuggab