ฉันจะสร้าง bytea แบบสุ่มได้อย่างไร


18

ฉันต้องการสร้างbyteaฟิลด์สุ่มที่มีความยาวตามอำเภอใจ (<1Gb) สำหรับการเติมข้อมูลการทดสอบ

วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?

คำตอบ:


20

เพิ่มคำตอบของแจ็คดักลาสเพื่อหลีกเลี่ยงความจำเป็นในการวนซ้ำ PL / PgSQL และการต่อข้อมูลไบต์คุณสามารถใช้:

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ค่ายิ่งใหญ่กว่า แม้ว่าฟังก์ชั่นดั้งเดิมจะเร็วกว่า 3x ถึงขนาด <50 ไบต์ แต่ฟังก์ชันนี้ปรับขนาดได้ดีกว่ามากสำหรับค่าที่มากกว่า

หรือใช้ฟังก์ชันส่วนขยาย C :

ฉันได้ใช้ตัวสร้าง bytea แบบสุ่มเป็นฟังก์ชันส่วนขยาย C แบบง่าย มันอยู่ในของฉันที่เก็บ scrapcode บน GitHub ดู README ที่นั่น

มัน nukes ประสิทธิภาพของรุ่น 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
ฉันพยายาม symlinking /dev/urandomเข้า/var/lib/pgsql/dataและการอ่านมันด้วยpg_read_file()สำหรับคะแนนโบนัสบ้า แต่น่าเสียดายที่pg_read_file()อ่านtextการป้อนข้อมูลผ่านการเข้ารหัสการแปลงดังนั้นจึงไม่สามารถอ่าน bytea หากคุณต้องการความเร็วสูงสุดจริงๆเขียนCฟังก์ชั่นส่วนขยายที่ใช้เครื่องกำเนิดไฟฟ้าจำนวนสุ่มหลอกรวดเร็วในการผลิตข้อมูลไบนารีและห่อมูลฐาน bytea รอบบัฟเฟอร์ :-)
เครก Ringer

1
@ แจ็คดักลาสฉันไม่สามารถช่วยได้ รุ่น C random_byteaส่วนขยายของ github.com/ringerc/scrapcode/tree/master/postgresql/…
Craig Ringer

1
อีกคำตอบที่ยอดเยี่ยม! จริงๆแล้วหนึ่งในดีที่สุดที่ฉันเคยเห็นมา ฉันไม่ได้ทดสอบส่วนขยาย แต่ฉันเชื่อว่าส่วนขยายนั้นทำงานได้ตามที่โฆษณาไว้
Erwin Brandstetter

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

การทดสอบการส่งออก:

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 ได้ดี มีประโยชน์
Craig Ringer

1
ฉันได้ปรับปรุงวิธีการของคุณเพื่อหลีกเลี่ยง PL / PgSQL และการต่อข้อมูลราคาแพง ดูคำตอบใหม่ โดยการใช้ string_agg แทน generate_series แทนการต่อข้อมูล PL / PgSQL แบบวนซ้อนบน bytea ฉันเห็นการปรับปรุงประสิทธิภาพ 150 เท่า
Craig Ringer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.