Bagaimana saya bisa menghasilkan bytea acak

18

Saya ingin dapat menghasilkan byteabidang acak dengan panjang acak (<1Gb) untuk mengisi data uji.

Apa cara terbaik untuk melakukan ini?

Jack Douglas
sumber

Jawaban:

20

Meningkatkan jawaban Jack Douglas untuk menghindari perlunya perulangan PL / PgSQL dan bytea, Anda dapat menggunakan:

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

Ini adalah SQLfungsi sederhana yang lebih murah untuk dipanggil daripada PL / PgSQL.

Perbedaan dalam kinerja karena metode agregasi yang diubah sangat besar untuk byteanilai yang lebih besar . Meskipun fungsi aslinya sebenarnya hingga 3x lebih cepat untuk ukuran <50 byte, yang satu ini jauh lebih baik untuk nilai yang lebih besar.

Atau gunakan fungsi ekstensi C :

Saya telah mengimplementasikan generator bytea acak sebagai fungsi ekstensi C sederhana. Itu ada di repositori scrapcode saya di GitHub . Lihat README di sana.

Itu nukes kinerja versi SQL di atas:

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
Craig Ringer
sumber
1
Yah, saya datang dengan solusi yang hampir sama, tetapi diuji hanya untuk nilai yang lebih rendah. Solusi There @ Jack adalah pemenang yang jelas. +1 untuk Anda karena tidak berhenti di sini :)
dezso
Terima kasih - ini luar biasa dan memprovokasi pemikiran. Saya pikir FROM generate_series(0, $1);perlu FROM generate_series(1, $1);. Sudahkah Anda mencoba rekursi? Pengujian terbatas saya menunjukkan bahwa skala ini lebih baik:
Jack Douglas
2
Saya mencoba menghubungkan /dev/urandomke /var/lib/pgsql/datadan membacanya dengan pg_read_file()bonus poin gila, tetapi sayangnya pg_read_file()membaca textinput melalui konversi pengkodean, sehingga tidak dapat membaca bytea. Jika Anda benar-benar menginginkan kecepatan maksimal, tulislah Cfungsi ekstensi yang menggunakan generator nomor acak pseudo-acak untuk menghasilkan data biner dan bungkus bytea datum di sekitar buffer :-)
Craig Ringer
1
@ JackDouglas saya tidak bisa menahannya. Versi ekstensi C dari random_bytea. github.com/ringerc/scrapcode/tree/master/postgresql/…
Craig Ringer
1
Jawaban bagus lainnya! Sebenarnya salah satu yang terbaik yang pernah saya lihat sejauh ini. Saya belum menguji ekstensi, tetapi saya percaya itu berfungsi seperti yang diiklankan.
Erwin Brandstetter
5

Saya ingin dapat menghasilkan bidang bytea acak yang panjangnya sewenang-wenang

Fungsi ini akan melakukannya, tetapi 1Gb akan memakan waktu lama karena tidak skala secara linear dengan panjang output:

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

tes keluaran:

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

Aku di sini

Jack Douglas
sumber
Penggunaan width_bucket yang bagus. Berguna.
Craig Ringer
1
Saya telah meningkatkan pendekatan Anda untuk menghindari PL / PgSQL dan loop concatenation mahal; lihat jawaban baru. Dengan menggunakan string_agg alih-alih menghasilkan_series alih-alih loop konkatasi PL / PgSQL pada bytea, saya melihat peningkatan kinerja 150 kali lipat.
Craig Ringer