Làm thế nào tôi có thể tạo ra một bytea ngẫu nhiên


18

Tôi muốn có thể tạo các byteatrường ngẫu nhiên có độ dài tùy ý (<1Gb) để điền dữ liệu thử nghiệm.

Cách nào là tốt nhất để thực hiện việc này?

Câu trả lời:


20

Nâng cao câu trả lời của Jack Douglas để tránh sự cần thiết phải lặp PL / PGQuery và kết nối tạm thời, bạn có thể sử dụng:

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

Đây là một SQLchức năng đơn giản mà rẻ hơn so với PL / PGQuery.

Sự khác biệt về hiệu suất do phương pháp tổng hợp thay đổi là rất lớn đối với các byteagiá trị lớn hơn . Mặc dù chức năng ban đầu thực sự nhanh hơn tới 3 lần đối với kích thước <50 byte, nhưng chức năng này có tỷ lệ tốt hơn nhiều đối với các giá trị lớn hơn.

Hoặc sử dụng chức năng mở rộng C :

Tôi đã triển khai một trình tạo bytea ngẫu nhiên như một hàm mở rộng C đơn giản. Nó nằm trong kho lưu trữ mã số của tôi trên GitHub . Xem README ở đó.

Nó ngăn chặn hiệu suất của phiên bản SQL trên:

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
Vâng, tôi đã đưa ra gần như cùng một giải pháp, nhưng chỉ thử nghiệm cho các giá trị thấp hơn. Có giải pháp của @ Jack là một người chiến thắng rõ ràng. +1 cho bạn vì đã không dừng ở đây :)
dezso

Cảm ơn bạn - điều này là tuyệt vời và kích thích tư duy. Tôi nghĩ FROM generate_series(0, $1);cần phải có FROM generate_series(1, $1);. Bạn đã thử đệ quy chưa? Thử nghiệm hạn chế của tôi ngụ ý rằng quy mô này tốt hơn:
Jack Douglas

2
Tôi cố gắng symlinking /dev/urandomvào /var/lib/pgsql/datavà đọc nó với pg_read_file()cho tiền thưởng điểm điên, nhưng tiếc là pg_read_file()đọc textđầu vào thông qua một chuyển đổi mã hóa, vì vậy nó không thể đọc bytea. Nếu bạn thực sự muốn tốc độ tối đa, hãy viết Chàm mở rộng sử dụng trình tạo số giả ngẫu nhiên nhanh để tạo dữ liệu nhị phân và bọc dữ liệu tạm thời xung quanh bộ đệm :-)
Craig Ringer

1
@JackDoureb Tôi không thể giúp nó. C phiên bản mở rộng của random_bytea. github.com/ringerc/scrapcode/tree/master/postgresql/ từ
Craig Ringer

1
Một câu trả lời tuyệt vời khác! Trên thực tế, một trong những điều tốt nhất tôi từng thấy cho đến nay. Tôi chưa thử nghiệm tiện ích mở rộng, nhưng tôi tin rằng nó hoạt động như quảng cáo.
Erwin Brandstetter

5

Tôi muốn có thể tạo các trường tạm thời ngẫu nhiên có độ dài tùy ý

Hàm này sẽ làm điều đó, nhưng 1Gb sẽ mất nhiều thời gian vì nó không mở rộng tuyến tính với độ dài đầu ra:

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

kiểm tra đầu ra:

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 ở đây


Sử dụng đẹp của width_bucket. Tiện dụng.
Craig Ringer

1
Tôi đã tăng cường cách tiếp cận của bạn để tránh vòng lặp PL / PGQuery và vòng lặp đắt tiền; xem câu trả lời mới Bằng cách sử dụng chuỗi_agg trên Gener_series thay vì vòng lặp nối PL / PGQuery trên bytea, tôi đang thấy hiệu suất cải thiện gấp 150 lần.
Craig Ringer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.