如何生成随机字节

Jac*_*las 21 postgresql testing random bytea

我希望能够生成bytea任意长度(<1Gb)的随机字段来填充测试数据。

这样做的最佳方法是什么?

Cra*_*ger 24

增强 Jack Douglas 的答案以避免需要 PL/PgSQL 循环和 bytea 连接,您可以使用:

CREATE OR REPLACE FUNCTION random_bytea(bytea_length integer)
RETURNS bytea AS $body$
    SELECT decode(string_agg(lpad(to_hex(width_bucket(random(), 0, 1, 256)-1),2,'0') ,''), 'hex')
    FROM generate_series(1, $1);
$body$
LANGUAGE 'sql'
VOLATILE
SET search_path = 'pg_catalog';
Run Code Online (Sandbox Code Playgroud)

这是一个简单的SQL函数,调用成本比 PL/PgSQL 便宜。

对于较大的bytea值,由于更改的聚合方法而导致的性能差异是巨大的。尽管对于小于 50 字节的大小,原始函数实际上快了 3 倍,但对于更大的值,这个函数的扩展性要好得多。

或者使用 C 扩展函数

我已经实现了一个随机字节生成器作为一个简单的 C 扩展函数。它在我的GitHub 上的剪贴代码存储库中。请参阅那里的自述文件。

它削弱了上述 SQL 版本的性能:

regress=# \a
regress=# \o /dev/null
regress=# \timing on
regress=# select random_bytea(2000000);
Time: 895.972 ms
regress=# drop function random_bytea(integer);
regress=# create extension random_bytea;
regress=# select random_bytea(2000000);
Time: 24.126 ms
Run Code Online (Sandbox Code Playgroud)

  • 我尝试将 `/dev/urandom` 符号链接到 `/var/lib/pgsql/data` 并使用 `pg_read_file()` 读取它以获得额外的疯狂点,但不幸的是 `pg_read_file()` 通过编码转换读取 `text` 输入,所以它不能读取bytea。如果您真的想要最大速度,请编写一个“C”扩展函数,该函数使用快速伪随机数生成器来生成二进制数据并在缓冲区周围包装字节数据:-) (2认同)

小智 9

pgcrypto扩展gen_random_bytes(count integer)

test=# create extension pgcrypto;
test=# select gen_random_bytes(16);
          gen_random_bytes
------------------------------------
 \xaeb98ae41489460c5292aafade4498ee
(1 row)
Run Code Online (Sandbox Code Playgroud)

只需create extension要做一次。


Jac*_*las 5

我希望能够生成任意长度的随机字节字段

这个函数可以做到,但 1Gb 需要很长时间,因为它不会随输出长度线性缩放:

create function random_bytea(p_length in integer) returns bytea language plpgsql as $$
declare
  o bytea := '';
begin 
  for i in 1..p_length loop
    o := o||decode(lpad(to_hex(width_bucket(random(), 0, 1, 256)-1),2,'0'), 'hex');
  end loop;
  return o;
end;$$;
Run Code Online (Sandbox Code Playgroud)

输出测试:

select random_bytea(2);

/*
|random_bytea|
|:-----------|
|\xcf99      |
*/

select random_bytea(10);

/*
|random_bytea          |
|:---------------------|
|\x781b462c3158db229b3c|
*/

select length(random_bytea(100000))
     , clock_timestamp()-statement_timestamp() time_taken;

/*
|length|time_taken     |
|-----:|:--------------|
|100000|00:00:00.654008|
*/
Run Code Online (Sandbox Code Playgroud)

dbfiddle在这里