How to generate a version 4 (random) UUID on Oracle?

前端 未结 9 1097
野性不改
野性不改 2020-12-05 10:37

This blog explains, that the output of sys_guid() is not random for every system:

http://feuerthoughts.blogspot.de/2006/02/watch-out-for-sequential-orac

9条回答
  •  悲&欢浪女
    2020-12-05 11:31

    Accepted answer from ceving is inconsistent with RFC4122: the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved should be set to zero and one, respectively. That makes y equal to 8,9,a or b in already mentioned by uğur-yeşilyurt format xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx

    My solution made point blank along RFC:

    create or replace function random_uuid return raw is
      /*
      Set the four most significant bits (bits 12 through 15) of the
          time_hi_and_version field to the 4-bit version number from
          Section 4.1.3.
      */
      v_time_hi_and_version raw(2) := utl_raw.bit_and(utl_raw.bit_or(dbms_crypto.randombytes(2), '4000'), '4FFF');
      /*
      Set the two most significant bits (bits 6 and 7) of the
          clock_seq_hi_and_reserved to zero and one, respectively.
      */
      v_clock_seq_hi_and_reserved raw(1) := utl_raw.bit_and(utl_raw.bit_or(dbms_crypto.randombytes(1), '80'), 'BF');
      /*
      Set all the other bits to randomly (or pseudo-randomly) chosen
          values.
      */
      v_time raw(6) := dbms_crypto.randombytes(6);
      v_clock_seq_low_and_node raw(7) := dbms_crypto.randombytes(7);
    begin
      return v_time || v_time_hi_and_version || v_clock_seq_hi_and_reserved || v_clock_seq_low_and_node;
    end random_uuid;
    

    EDIT:

    Although first implementation easy to understand it's rather inefficient. Next solution is 3 to 4 times faster.

    create or replace function random_uuid2 return raw is
      v_uuid raw(16) := dbms_crypto.randombytes(16);
    begin
       v_uuid :=  utl_raw.bit_or(v_uuid, '00000000000040008000000000000000');
       v_uuid := utl_raw.bit_and(v_uuid, 'FFFFFFFFFFFF4FFFBFFFFFFFFFFFFFFF');
      return v_uuid;
    end;
    

    This test demostrates that random_uuid takes about one millisecond and random_uuid2 only 250 microseconds. Concatenation in the first version consumed too much time;

    declare
       dummy_uuid raw(16);
    begin
       for i in 1 .. 20000 loop
          --dummy_uuid := random_uuid;
          dummy_uuid := random_uuid2;
       end loop;
    end;
    

提交回复
热议问题