你如何创build一个适合于PostgreSQL中的会话ID的随机string?
我想使用PostgreSQL在会话validation中使用一个随机string。 我知道我可以得到一个随机数与SELECT random()
,所以我尝试了SELECT md5(random())
,但是这是行不通的。 我该怎么做?
我build议这个简单的解决scheme:
这是一个非常简单的函数,它返回给定长度的随机string:
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)
你可以修复你的初始尝试像这样:
SELECT md5(random()::text);
比其他一些build议简单得多。 🙂
基于Marcin的解决scheme,您可以使用任意字母表(在这种情况下,所有62个ASCII字母数字字符):
SELECT array_to_string(array ( select substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', trunc(random() * 62)::integer + 1, 1) FROM generate_series(1, 12)), '');
我最近在玩PostgreSQL,我想我find了一个更好的解决scheme,只使用内置的PostgreSQL方法 – 没有pl / pgsql。 唯一的限制是它目前只生成UPCASEstring,数字或小写string。
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
方法的第二个参数决定了string的长度。
虽然默认情况下没有激活,但您可以激活其中一个核心扩展:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
然后你的语句变成一个简单的调用gen_salt(),它会生成一个随机string:
select gen_salt('md5') from generate_series(1,4); gen_salt ----------- $1$M.QRlF4U $1$cv7bNJDM $1$av34779p $1$ZQkrCXHD
前导号码是一个哈希标识符。 几种algorithm都有自己的标识符:
- md5:$ 1 $
- bf:$ 2a $ 06 $
- des:没有标识符
- xdes:_J9 ..
有关扩展的更多信息:
- pgCrypto: http : //www.postgresql.org/docs/9.2/static/pgcrypto.html
- 包括扩展: http : //www.postgresql.org/docs/9.2/static/contrib.html
编辑
正如Evan Carrol所指出的那样,你可以使用gen_random_uuid()
你可以从UUID中获得128位的随机数。 这是在现代PostgreSQL中完成工作的方法。
CREATE EXTENSION pgcrypto; SELECT gen_random_uuid(); gen_random_uuid -------------------------------------- 202ed325-b8b1-477f-8494-02475973a28f
也可能值得阅读关于UUID的文档
数据typesuuid存储由RFC 4122,ISO / IEC 9834-8:2005和相关标准定义的通用唯一标识符(UUID)。 (有些系统将此数据types称为全局唯一标识符,或GUID)。此标识符是一个128位的数量 ,由select的algorithm生成,以使其他人不会生成相同的标识符在已知的宇宙中使用相同的algorithm。 因此,对于分布式系统,这些标识符提供了比序列发生器更好的唯一性保证,序列发生器在单个数据库中是唯一的。
与UUID的冲突是多less,还是可以猜测的? 假设他们是随机的,
大约100万亿的第4版UUID需要产生10亿个单一重复(“碰撞”)机会。 只有在产生了261个UUID(2.3×1018或2.3%)后,一次碰撞的机会才上升到50%。 将这些数字与数据库相关联,并考虑第4版UUID碰撞概率是否可忽略的问题,考虑包含2.3版本4 UUID的文件,其中50%的概率包含一个UUID冲突。 假设没有其他数据或开销,它将是36艾字节大小,比现有最大的数据库大几千倍,大小为PB级。 以每秒10亿个UUID的速率生成文件的UUID需要73年的时间。 如果没有备份或冗余,还需要大约360万个10 TB的硬盘或磁带存储。 以典型的“磁盘到缓冲”传输速率读取文件1千兆每秒将需要超过3000年的单个处理器。 由于驱动器的不可恢复的读错误率是每读取1018位1位,文件最多只能包含1020位,因此只要读取文件一次就会导致至less大约100倍的错误,读取UUID而不是重复。 存储,networking,电源和其他硬件和软件错误无疑会比UUID复制问题频繁几千倍。 – 来源维基百科
综上所述,
- UUID是标准化的。
-
gen_random_uuid()
是128位随机存储的128位(2 ** 128个组合)。 0垃圾。 -
random()
只在PostgreSQL中产生52位随机数(2 ** 52个组合)。 - 作为UUID存储的
md5()
是128位,但它只能随机input( 如果使用random()
则为52位 ) - 作为文本存储的
md5()
是288位,但它只能和它的input一样随机( 如果使用random()
则是52位 ) – 是UUID大小的两倍和随机性的一小部分) -
md5()
作为一个散列,可以这样优化,它不会有效地做很多。 - UUID是高效的存储:PostgreSQL提供了一个types,正是128位。 不像
text
和varchar
等存储为string长度开销的varlena
。 - PostgreSQL漂亮的UUID附带一些默认的运算符,铸件和特征。
我不认为你正在寻找一个随机的string本身。 会话validation需要的是一个保证唯一的string。 你是否存储会话validation信息以进行审计? 在这种情况下,您需要string在会话之间是唯一的。 我知道两个相当简单的方法:
- 使用一个序列。 适用于单个数据库。
- 使用UUID。 通用独特,在分布式环境中也是如此。
UUID由于其生成algorithm而保证是唯一的; 实际上,在任何机器上,无论何时都会生成两个相同的数字(请注意,这比在随机string上的周期性要比UUID小得多)。
您需要加载uuid-ossp扩展才能使用UUID。 安装完成后,请在您的SELECT,INSERT或UPDATE调用中调用任何可用的uuid_generate_vXXX()函数。 uuidtypes是一个16字节的数字,但它也有一个string表示。
select * from md5(to_char(random(), '0.9999999999999999'));
请使用string_agg
!
SELECT string_agg (substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ceil (random() * 62)::integer, 1), '') FROM generate_series(1, 45);
我正在用MD5来生成一个UUID。 我只想要一个比random ()
整数更多的随机值。
INTEGER参数定义string的长度。 保证以相同的概率覆盖所有62个字母(不同于在互联网上stream动的其他解决scheme)。
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;
@Kaviusbuild议使用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 encode(decode(md5(random()::text), 'hex')||decode(md5(random()::text), 'hex'), 'base64')
你也可以使用now()
函数:
SELECT md5(now()::text);