如何在Oracle上生成版本4(随机)UUID?

cev*_*ing 17 oracle uuid

这篇博客解释说,sys_guid()每个系统的输出都不是随机的:

http://feuerthoughts.blogspot.de/2006/02/watch-out-for-sequential-oracle-guids.html

不幸的是我必须使用这样的系统.

如何确保获得随机UUID?有可能sys_guid()吗?如果不是如何在Oracle上可靠地获取随机UUID?

Jon*_*ler 26

这是一个完整的例子,基于@Pablo Santa Cruz的答案和你发布的代码.

我不确定你为什么收到错误信息.这可能是SQL Developer的一个问题.在SQL*Plus中运行它时,一切正常,并添加一个函数:

   create or replace and compile
   java source named "RandomUUID"
   as
   public class RandomUUID
   {
      public static String create()
      {
              return java.util.UUID.randomUUID().toString();
      }
   }
   /
Run Code Online (Sandbox Code Playgroud)
Java created.
Run Code Online (Sandbox Code Playgroud)
   CREATE OR REPLACE FUNCTION RandomUUID
   RETURN VARCHAR2
   AS LANGUAGE JAVA
   NAME 'RandomUUID.create() return java.lang.String';
   /
Run Code Online (Sandbox Code Playgroud)
Function created.
Run Code Online (Sandbox Code Playgroud)
   select randomUUID() from dual;
Run Code Online (Sandbox Code Playgroud)
RANDOMUUID()
--------------------------------------------------------------
4d3c8bdd-5379-4aeb-bc56-fcb01eb7cc33
Run Code Online (Sandbox Code Playgroud)

SYS_GUID如果可能的话,我会坚持下去.查看My Oracle Support上的ID 1371805.1 - 该错误应该在11.2.0.3中修复.

编辑

哪一个更快取决于功能的使用方式.

在SQL中使用时,Java版本看起来稍快一些.但是,如果您要在PL/SQL上下文中使用此函数,则PL/SQL函数的速度大约是其两倍.(可能是因为它避免了引擎之间切换的开销.)

这是一个简单的例子:

--Create simple table
create table test1(a number);
insert into test1 select level from dual connect by level <= 100000;
commit;

--SQL Context: Java function is slightly faster
--
--PL/SQL: 2.979, 2.979, 2.964 seconds
--Java: 2.48, 2.465, 2.481 seconds
select count(*)
from test1
--where to_char(a) > random_uuid() --PL/SQL
where to_char(a) > RandomUUID() --Java
;

--PL/SQL Context: PL/SQL function is about twice as fast
--
--PL/SQL: 0.234, 0.218, 0.234
--Java: 0.52, 0.515, 0.53
declare
    v_test1 raw(30);
    v_test2 varchar2(36);
begin
    for i in 1 .. 10000 loop
        --v_test1 := random_uuid; --PL/SQL
        v_test2 := RandomUUID; --Java
    end loop;
end;
/
Run Code Online (Sandbox Code Playgroud)

版本4 GUID不是完全随机的.一些字节应该是固定的.我不确定为什么要这样做,或者它是否重要,但根据https://www.cryptosys.net/pki/uuid-rfc4122.html:

生成版本4 UUID的过程如下:

Generate 16 random bytes (=128 bits)
Adjust certain bits according to RFC 4122 section 4.4 as follows:
    set the four most significant bits of the 7th byte to 0100'B, so the high nibble is "4"
    set the two most significant bits of the 9th byte to 10'B, so the high nibble will be one of "8", "9", "A", or "B".
Encode the adjusted bytes as 32 hexadecimal digits
Add four hyphen "-" characters to obtain blocks of 8, 4, 4, 4 and 12 hex digits
Output the resulting 36-character string "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
Run Code Online (Sandbox Code Playgroud)

Java版本的值似乎符合标准.


小智 15

/sf/answers/762952431/

以下函数使用sys_guid()并将其转换为uuid格式:

create or replace function random_uuid return VARCHAR2 is
  v_uuid VARCHAR2(40);
begin
  select regexp_replace(rawtohex(sys_guid()), '([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})', '\1-\2-\3-\4-\5') into v_uuid from dual;
  return v_uuid;
end random_uuid;
Run Code Online (Sandbox Code Playgroud)

它不需要创建dbms_crypto包并授予它.

  • 此功能在所有平台上都不是随机的.例如,在Solaris上,每次执行时只会更改一个或两个字符. (2认同)

cev*_*ing 9

我现在使用它作为一种解决方法:

create or replace function random_uuid return RAW is
  v_uuid RAW(16);
begin
  v_uuid := sys.dbms_crypto.randombytes(16);
  return (utl_raw.overlay(utl_raw.bit_or(utl_raw.bit_and(utl_raw.substr(v_uuid, 7, 1), '0F'), '40'), v_uuid, 7));
end random_uuid;

该功能需要dbms_cryptoutl_raw.两者都需要执行授权.

grant execute on sys.dbms_crypto to uuid_user;
Run Code Online (Sandbox Code Playgroud)


Kir*_*ill 6

对我来说获得基于 Java 的函数的最简单、最短的方法是:

create or replace function random_uuid return varchar2 as
language java
name 'java.util.UUID.randomUUID() return String';
Run Code Online (Sandbox Code Playgroud)

我无法完全理解为什么如果我添加它就无法编译.toString()