PostgreSQLを使用したセッション検証で使用するランダムな文字列を作成したいと思います。で乱数を取得できることがわかっているSELECT random()
ので、を試しましたSELECT md5(random())
が、うまくいきません。これどうやってするの?
random()
必要性がない場合)。それが私が想定するものではない場合、私の答えは、代わりに洗練された質問に応える必要があります。
PostgreSQLを使用したセッション検証で使用するランダムな文字列を作成したいと思います。で乱数を取得できることがわかっているSELECT random()
ので、を試しましたSELECT md5(random())
が、うまくいきません。これどうやってするの?
random()
必要性がない場合)。それが私が想定するものではない場合、私の答えは、代わりに洗練された質問に応える必要があります。
回答:
私はこの簡単な解決策を提案します:
これは、指定された長さのランダムな文字列を返す非常に単純な関数です。
Create or replace function random_string(length integer) returns text as
$$
declare
chars text[] := '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}';
result text := '';
i integer := 0;
begin
if length < 0 then
raise exception 'Given length cannot be less than 0';
end if;
for i in 1..length loop
result := result || chars[1+random()*(array_length(chars, 1)-1)];
end loop;
return result;
end;
$$ language plpgsql;
そして使用法:
select random_string(15);
出力例:
select random_string(15) from generate_series(1,15);
random_string
-----------------
5emZKMYUB9C2vT6
3i4JfnKraWduR0J
R5xEfIZEllNynJR
tMAxfql0iMWMIxM
aPSYd7pDLcyibl2
3fPDd54P5llb84Z
VeywDb53oQfn9GZ
BJGaXtfaIkN4NV8
w1mvxzX33NTiBby
knI1Opt4QDonHCJ
P9KC5IBcLE0owBQ
vvEEwc4qfV4VJLg
ckpwwuG8YbMYQJi
rFf6TchXTO3XsLs
axdQvaLBitm6SDP
(15 rows)
chars[1+random()*(array_length(chars, 1)-1)]
ましたchars[ceil(61 * random())]
ORDER BY random()
。どちらが速いですか?
次のように最初の試行を修正できます。
SELECT md5(random()::text);
他のいくつかの提案よりもはるかに単純です。:-)
SELECT concat(md5(random()::text), md5(random()::text));
そして、あなたが途中でどこかに(例えば50文字)を望んでいた場合は、そのサブ取ることができる: SELECT substr(concat(md5(random()::text), md5(random()::text)), 0, 50);
gen_random_uuid()
、より速く、よりランダムに、より効率的にデータベースに保存される、まったく異なる方法を確認してください。
Marcinのソリューションに基づいて、任意のアルファベット(この場合は62文字のASCII英数字)を使用することができます。
SELECT array_to_string(array
(
select substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', trunc(random() * 62)::integer + 1, 1)
FROM generate_series(1, 12)), '');
Check out this for a totally different method using gen_random_uuid()
:より速く、よりランダムに、より効率的にデータベースに保存されます。
UUIDから128ビットのランダムを取得できます。これは、最新のPostgreSQLで作業を行うための方法です。
CREATE EXTENSION pgcrypto;
SELECT gen_random_uuid();
gen_random_uuid
--------------------------------------
202ed325-b8b1-477f-8494-02475973a28f
データ型uuidは、RFC 4122、ISO / IEC 9834-8:2005、および関連する規格で定義されている Universally Unique Identifier(UUID)を格納します。(一部のシステムでは、このデータ型をグローバル一意識別子(GUID)と呼びます。)この識別子は、同じ識別子が他の誰かによって生成される可能性を非常に低くするように選択されたアルゴリズムによって生成される128ビットの数量です。同じアルゴリズムを使用して既知の宇宙で。したがって、分散システムの場合、これらの識別子は、単一のデータベース内でのみ一意であるシーケンスジェネレーターよりも優れた一意性を保証します。
UUIDとの衝突はどれくらいまれですか?それらがランダムであると仮定すると、
単一の重複(「衝突」)の可能性が10億分の1になるには、約100兆のバージョン4 UUIDを生成する必要があります。1回の衝突の可能性は、261 UUID(2.3 x 10 ^ 18または2.3 quintillion)が生成された後にのみ50%に上昇します。これらの数値をデータベースに関連付け、バージョン4 UUIDの衝突の可能性が無視できるかどうかの問題を考慮して、50%の確率で1つのUUID衝突が含まれる2.3キロバイトのバージョン4 UUIDを含むファイルを検討してください。他のデータやオーバーヘッドがないと仮定すると、サイズは36エクサバイトになり、現在存在する最大のデータベース(ペタバイト程度)の数千倍になります。1秒あたり10億個のUUIDが生成されるとすると、ファイルのUUIDを生成するのに73年かかります。また、約3が必要です。バックアップや冗長性がないと仮定して、600万個の10テラバイトのハードドライブまたはテープカートリッジを保存します。1ギガビット/秒の一般的な「ディスクからバッファ」への転送速度でファイルを読み取るには、単一のプロセッサで3000年以上必要です。ドライブの回復不可能な読み取りエラー率は、1018ビットの読み取りあたり最大1ビットであるため、ファイルには約1020ビットが含まれますが、ファイルを端から端まで一度だけ読み取ると、少なくとも約100倍多くのミスが発生します。重複よりUUIDを読み取ります。ストレージ、ネットワーク、電源、およびその他のハードウェアとソフトウェアのエラーは、間違いなくUUIDの複製の問題より数千倍も頻繁に発生します。1ギガビット/秒の転送速度では、1つのプロセッサで3000年以上必要です。ドライブの回復不可能な読み取りエラー率は、1018ビットの読み取りあたり最大1ビットであるため、ファイルには約1020ビットが含まれますが、ファイルを端から端まで一度だけ読み取ると、少なくとも約100倍多くのミスが発生します。重複よりUUIDを読み取ります。ストレージ、ネットワーク、電源、およびその他のハードウェアとソフトウェアのエラーは、間違いなくUUIDの複製の問題より数千倍も頻繁に発生します。1ギガビット/秒の転送速度では、1つのプロセッサで3000年以上必要です。ドライブの回復不可能な読み取りエラー率は、1018ビットの読み取りあたり最大1ビットであるため、ファイルには約1020ビットが含まれますが、ファイルを端から端まで一度だけ読み取ると、少なくとも約100倍多くのミスが発生します。重複よりUUIDを読み取ります。ストレージ、ネットワーク、電源、およびその他のハードウェアとソフトウェアのエラーは、間違いなくUUIDの複製の問題より数千倍も頻繁に発生します。
ソース:ウィキペディア
要約すれば、
gen_random_uuid()
128ビット(2 ** 128の組み合わせ)に格納された128ビットのランダムです。0-廃棄物。random()
PostgreSQLで52ビットのランダム(2 ** 52の組み合わせ)のみを生成します。md5()
UUIDとして保存されるのは128ビットですが、入力と同じくらいランダムにすることができます(を使用する場合は52ビットrandom()
)md5()
テキストとして保存されるのは288ビットですが、入力と同じくらいランダムにしか使用できません(使用している場合は52ビットrandom()
)-UUIDのサイズの2倍以上、ランダム性の一部)md5()
ハッシュとしては、最適化できるため、あまり効果がありません。text
and とは異なります。varchar
varlena
私は最近PostgreSQLを使用していましたが、組み込みのPostgreSQLメソッドのみを使用して、少し優れたソリューションを見つけたと思います。pl/ pgsqlは使用しません。唯一の制限は、現在UPCASE文字列、数値、または小文字の文字列のみを生成することです。
template1=> SELECT array_to_string(ARRAY(SELECT chr((65 + round(random() * 25)) :: integer) FROM generate_series(1,12)), '');
array_to_string
-----------------
TFBEGODDVTDM
template1=> SELECT array_to_string(ARRAY(SELECT chr((48 + round(random() * 9)) :: integer) FROM generate_series(1,12)), '');
array_to_string
-----------------
868778103681
generate_series
メソッドの2番目の引数は、文字列の長さを指定します。
array_to_string(ARRAY(SELECT chr((65 + round((random()+my_id-my) * 25)) :: integer) FROM generate_series(1,8)), '')
array_to_string(ARRAY(SELECT chr((65 + round((random() * 25 + id) :: integer % 25 )) :: integer) FROM generate_series(1, 60)), '');
ぜひご利用くださいstring_agg
!
SELECT string_agg (substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ceil (random() * 62)::integer, 1), '')
FROM generate_series(1, 45);
これをMD5で使用してUUIDも生成しています。random ()
整数よりもビット数の多いランダムな値が必要です。
random()
必要なビット数が得られるまで連結できると思います。しかたがない。
デフォルトではアクティブではありませんが、コア拡張の1つをアクティブにすることができます。
CREATE EXTENSION IF NOT EXISTS pgcrypto;
次に、ステートメントは、ランダムな文字列を生成するgen_salt()への単純な呼び出しになります。
select gen_salt('md5') from generate_series(1,4);
gen_salt
-----------
$1$M.QRlF4U
$1$cv7bNJDM
$1$av34779p
$1$ZQkrCXHD
先頭の番号はハッシュ識別子です。それぞれ独自の識別子を持ついくつかのアルゴリズムが利用可能です:
拡張機能の詳細:
編集
Evan Carrolによって示されているように、v9.4以降では、 gen_random_uuid()
$1$
ますか?これはハッシュ型の識別子(md5 == 1)で、残りはランダム化された値です。
それ自体がランダムな文字列を探しているとは思いません。セッション検証に必要なのは、一意であることが保証されている文字列です。監査用のセッション検証情報を保存していますか?その場合、セッション間で一意の文字列が必要です。私は2つのかなり単純なアプローチを知っています。
UUIDは、生成アルゴリズムによって一意であることが保証されています。事実上非常にあなたは、任意の時点で、これまでに(これはUUIDに比べてはるかに小さい周期性を持つランダムな文字列、上よりもはるかに強力であることに注意)を任意のマシン上に2つの同一の番号を生成する可能性は低いです。
UUIDを使用するには、uuid-ossp拡張機能をロードする必要があります。インストールしたら、SELECT、INSERT、またはUPDATE呼び出しで使用可能なuuid_generate_vXXX()関数のいずれかを呼び出します。uuidタイプは16バイトの数値ですが、文字列表現も持っています。
INTEGERパラメータは文字列の長さを定義します。62の英数字すべてを同等の確率でカバーすることが保証されています(インターネット上に浮かんでいる他のいくつかのソリューションとは異なります)。
CREATE OR REPLACE FUNCTION random_string(INTEGER)
RETURNS TEXT AS
$BODY$
SELECT array_to_string(
ARRAY (
SELECT substring(
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
FROM (ceil(random()*62))::int FOR 1
)
FROM generate_series(1, $1)
),
''
)
$BODY$
LANGUAGE sql VOLATILE;
Check out this for a totally different method using gen_random_uuid()
:より速く、よりランダムに、より効率的にデータベースに保存されます。
gen_random_uuid()
言えば、私が知る限り、バージョン9.4 に登場しました。これは2014-12-18にリリースされたもので、あなたが反対票を投じてから1年以上経過しています。追加のnitpick:答えはほんの3 1/2歳です:-)しかし、あなたが正しい、これが私たちが持っているのでgen_random_uuid()
、これが使用されるべきものです。したがって、私はあなたの答えを賛成します。
@Kaviusはの使用を推奨しましたpgcrypto
が、の代わりにgen_salt
どうgen_random_bytes
ですか?そして、sha512
代わりにmd5
どうですか?
create extension if not exists pgcrypto;
select digest(gen_random_bytes(1024), 'sha512');
ドキュメント:
F.25.5。ランダムデータ関数
gen_random_bytes(count integer)はbyteaを返します
暗号的に強力なランダムバイトのカウントを返します。一度に最大1024バイトを抽出できます。これは、乱数発生器プールのドレインを回避するためです。
select * from md5(to_char(random(), '0.9999999999999999'));
select encode(decode(md5(random()::text), 'hex')||decode(md5(random()::text), 'hex'), 'base64')