22

このブログでは、の出力はsys_guid()すべてのシステムでランダムではないことを説明しています。

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

残念ながら、私はそのようなシステムを使わなければなりません。

ランダムなUUIDを確実に取得するにはどうすればよいですか?それは可能sys_guid()ですか?OracleでランダムなUUIDを確実に取得する方法がない場合はどうすればよいですか?

4

9 に答える 9

31

@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();
      }
   }
   /
Java created.
   CREATE OR REPLACE FUNCTION RandomUUID
   RETURN VARCHAR2
   AS LANGUAGE JAVA
   NAME 'RandomUUID.create() return java.lang.String';
   /
Function created.
   select randomUUID() from dual;
RANDOMUUID()
--------------------------------------------------------------
4d3c8bdd-5379-4aeb-bc56-fcb01eb7cc33

しかし、可能であれば私は固執しSYS_GUIDます。My Oracle Support で ID 1371805.1 を確認してください。このバグは 11.2.0.3 で修正されていると思われます。

編集

どちらが速いかは、関数の使用方法によって異なります。

SQLで使うとJava版の方が若干速いようです。ただし、この関数を PL/SQL コンテキストで使用する場合は、PL/SQL 関数の方が約 2 倍高速です。(おそらく、エンジン間の切り替えのオーバーヘッドを回避するためです。)

簡単な例を次に示します。

--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;
/

バージョン 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"

Java バージョンの値は、標準に準拠しているように見えます。

于 2012-12-20T06:33:33.060 に答える
17

https://stackoverflow.com/a/10899320/1194307

次の関数は 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;

dbms_crypto パッケージを作成して付与する必要はありません。

于 2013-11-06T05:25:15.573 に答える
13

私は今これを回避策として使用しています:

create or replace function random_uuid return RAW は
  v_uuid RAW(16);
始める
  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));
random_uuid を終了します。

関数にはdbms_cryptoとが必要utl_rawです。どちらも実行権限が必要です。

grant execute on sys.dbms_crypto to uuid_user;
于 2012-12-19T16:27:29.907 に答える
3

Javaプロシージャを記述してコンパイルし、Oracle内で実行できます。その手順では、次を使用できます。

UUID uuid = UUID.randomUUID();
return uuid.toString();

目的の値を生成します。

OracleでJavaプロシージャをコンパイルする方法に関するリンクは次のとおりです。

于 2012-12-19T11:38:28.323 に答える
1

uuid バージョン 4 を生成し、任意のタイプの GUID をフォーマットする、私と友人の 1 人が作成した純粋な plsql 関数がいくつかあります。また、2 つの方法で記述されたフォーマッタも含まれます。1 つの連結文字列と 1 つの正規表現を使用して uuid をフォーマットする

CREATE OR REPLACE FUNCTION RANDOM_UUD_RAW
  RETURN RAW IS V_UUID RAW(16);
  BEGIN V_UUID := SYS.DBMS_CRYPTO.Randombytes(16);
    V_UUID := UTL_RAW.Overlay(UTL_RAW.Bit_or(UTL_RAW.Bit_and(UTL_RAW.Substr(V_UUID, 7, 1), '0F'), '40'), V_UUID, 7, 1);
    V_UUID := UTL_RAW.Overlay(UTL_RAW.Bit_or(UTL_RAW.Bit_and(UTL_RAW.Substr(V_UUID, 9, 1), '3F'), '80'), V_UUID, 9, 1);
    RETURN V_UUID;
  END RANDOM_UUD_RAW; --
CREATE OR REPLACE FUNCTION UUID_FORMATTER_CONCAT(V_UUID RAW)
  RETURN VARCHAR2 IS V_STR VARCHAR2(36);
  BEGIN V_STR := lower(SUBSTR(V_UUID, 1, 8) || '-' || SUBSTR(V_UUID, 9, 4) || '-' || SUBSTR(V_UUID, 13, 4) || '-' || SUBSTR(V_UUID, 17, 4) || '-' || SUBSTR(V_UUID, 21));
    RETURN V_STR;
  END UUID_FORMATTER_CONCAT; --
CREATE OR REPLACE FUNCTION UUID_FORMATTER_REGEX(V_UUID RAW)
  RETURN VARCHAR2 IS V_STR VARCHAR2(36);
  BEGIN V_STR := lower(regexp_replace(V_UUID, '(.{8})(.{4})(.{4})(.{4})(.{12})', '\1-\2-\3-\4-\5'));
    RETURN V_STR;
  END UUID_FORMATTER_REGEX; --
CREATE OR REPLACE FUNCTION RANDOM_UUID_STR
  RETURN VARCHAR2 AS BEGIN RETURN UUID_FORMATTER_CONCAT(RANDOM_UUD_RAW());
  END RANDOM_UUID_STR; --
CREATE OR REPLACE FUNCTION RANDOM_UUID_STR_REGEX
  RETURN VARCHAR2 AS BEGIN RETURN UUID_FORMATTER_REGEX(RANDOM_UUD_RAW());
  END RANDOM_UUID_STR_REGEX;


于 2019-08-25T08:01:35.817 に答える