Nasıl rastgele bir bytea üretebilirim?


18

byteaTest verilerini doldurmak için rastgele uzunluktaki (<1Gb) rasgele alanlar oluşturabilmek istiyorum .

Bunu yapmanın en iyi yolu nedir?

Yanıtlar:


20

PL / PgSQL döngüsüne ve bayt birleşimine gerek kalmaması için Jack Douglas'ın cevabını geliştirmek için şunları kullanabilirsiniz:

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

SQLPL / PgSQL'den daha ucuz, basit bir işlev.

Değişen toplama yöntemine bağlı olarak performans farkı, daha büyük byteadeğerler için çok büyüktür . Orijinal işlev aslında <50 baytlık boyutlar için 3 kata kadar daha hızlı olsa da, bu daha büyük değerler için çok daha iyi ölçeklenir.

Veya bir C uzantısı işlevi kullanın :

Basit bir C uzatma fonksiyonu olarak rastgele bir bytea jeneratörü uyguladım. Benim öyle GitHub'dan scrapcode depo . Orada README'ye bakın.

Yukarıdaki SQL sürümünün performansını azaltır:

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
Neredeyse aynı çözümü buldum, ancak sadece daha düşük değerler için test ettim. @ Jack'in çözümü belli oldu. Burada
durmadığınız

Teşekkür ederim - bu mükemmel ve kışkırtıcı düşündüm. Bence FROM generate_series(0, $1);olmalı FROM generate_series(1, $1);. Özyinelemeyi denediniz mi? Sınırlı testlerim bunun daha iyi ölçeklendiğini ima ediyor:
Jack Douglas

2
Ben sembolik bağlantılarını çalıştı /dev/urandomiçine /var/lib/pgsql/datave birlikte okumaya pg_read_file()deli noktaları bonusu, fakat maalesef pg_read_file()okur texto bytea türünde bir değer okuyamaz böylece, bir kodlama dönüşümü yoluyla girişi. Eğer gerçekten maksimum hız istiyorsanız, bir yazma Cikili veri üretmek ve :-) tampon etrafında bir bytea verisini sarmak için hızlı sözde rasgele sayı üreteci kullanan uzatma fonksiyonu
Craig Ringer

1
@JackDouglas Yardım edemedim. C uzantısı sürümü random_bytea. github.com/ringerc/scrapcode/tree/master/postgresql/…
Craig Ringer

1
Başka bir mükemmel cevap! Aslında şimdiye kadar gördüğüm en iyilerden biri. Uzantıyı test etmedim, ancak reklamı yapılan şekilde çalıştığına inanıyorum.
Erwin Brandstetter

5

Rastgele uzunluktaki rastgele bytea alanları üretebilmek istiyorum

Bu işlev bunu yapar, ancak 1Gb uzun süre alacaktır, çünkü çıktı uzunluğu ile doğrusal olarak ölçeklenmez:

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

çıkış testi:

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 buraya


Width_bucket'ın güzel kullanımı. Kullanışlı.
Craig Ringer

1
PL / PgSQL ve pahalı birleştirme döngüsünden kaçınmak için yaklaşımınızı geliştirdim; yeni cevaba bakınız. Bytea üzerinde bir PL / PgSQL birleştirme döngüsü yerine string_agg kullanarak create_series kullanarak performansında 150 kat iyileşme görüyorum.
Craig Ringer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.