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


18

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

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

回答:


20

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

これSQLは、PL / PgSQLよりも呼び出しが簡単な単純な関数です。

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

または、C拡張機能を使用します

単純なC拡張関数として、ランダムなbyteaジェネレーターを実装しました。それは私の中にありますGitHubの上scrapcodeリポジトリ。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

1
まあ、私はほぼ同じソリューションを思いつきましたが、低い値についてのみテストしました。そこで@Jackのソリューションが明確な勝者となりました。ここで止まらないことに対するあなたのための+1 :)
dezso

ありがとう-これは素晴らしいと考えられます。FROM generate_series(0, $1);する必要があると思いますFROM generate_series(1, $1);。再帰を試しましたか?私の限られたテストでは、このスケールがより良い意味:
ジャック・ダグラス

2
私はシンボリックリンクしようとした/dev/urandom/var/lib/pgsql/dataし、それを読んでpg_read_file()クレイジーなポイントをボーナスのため、残念ながらpg_read_file()読みtext、それはbytea型を読み取ることができないので、エンコーディング変換を介して入力します。本当に最高の速度が必要な場合Cは、高速擬似乱数ジェネレーターを使用してバイナリデータを生成し、バッファーの周りにbyteaデータをラップする拡張関数を作成してください:-)
クレイグリンガー

1
@JackDouglas仕方なかった。C拡張バージョンrandom_byteagithub.com/ringerc/scrapcode/tree/master/postgresql/...
クレイグリンガー

1
別の優れた答え!実際のところ、私が今まで見た中で最高のものの一つです。私は拡張機能をテストしていませんが、宣伝どおりに機能すると信じています。
アーウィンブランドステッター

5

任意の長さのランダムな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


width_bucketの素晴らしい使用法。ハンディ。
クレイグリンガー

1
PL / PgSQLと高価な連結ループを回避するために、アプローチを強化しました。新しい答えをご覧ください。byteaでPL / PgSQL連結ループの代わりにgenerate_seriesよりstring_aggを使用することにより、パフォーマンスが150倍改善されます。
クレイグリンガー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.