web-dev-qa-db-ja.com

ランダムbyteaを生成するにはどうすればよいですか

テストデータを入力するために、任意の長さ(<1Gb)のランダムbyteaフィールドを生成できるようにしたいと思います。

これを行う最良の方法は何ですか?

PL/PgSQLループとbytea連結の必要性を回避するためにJack Douglasの答えを拡張するには、次を使用できます。

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

これは、PL/PgSQLよりも安価に呼び出すことができる単純なSQL関数です。

集計方法の変更によるパフォーマンスの違いは、byteaの値が大きいほど大きくなります。元の関数は、実際にはサイズが50バイト未満の場合に最大3倍高速ですが、この関数は、値が大きいほどスケーリングが向上します。

またはC拡張関数を使用します

ランダムbyteaジェネレーターを単純なC拡張関数として実装しました。私の GitHubのスクラップコードリポジトリ にあります。 READMEを参照してください。

上記の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
20
Craig Ringer

任意の長さのランダムなbyteaフィールドを生成できるようにしたい

この関数はそれを行いますが、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;$$;

出力テスト:

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

dbfiddle ここ

pgcrypto 拡張にはgen_random_bytes(count integer)があります:

test=# create extension pgcrypto;
test=# select gen_random_bytes(16);
          gen_random_bytes
------------------------------------
 \xaeb98ae41489460c5292aafade4498ee
(1 row)

create extensionは1回だけ実行する必要があります。

1
Martin Tournoij