Cách tốt nhất để chọn các hàng ngẫu nhiên PostgreSQL


344

Tôi muốn một lựa chọn ngẫu nhiên các hàng trong PostgreSQL, tôi đã thử điều này:

select * from table where random() < 0.01;

Nhưng một số người khác khuyên điều này:

select * from table order by random() limit 1000;

Tôi có một bảng rất lớn với 500 Triệu hàng, tôi muốn nó nhanh.

Cách tiếp cận nào tốt hơn? Sự khác biệt là gì? Cách tốt nhất để chọn hàng ngẫu nhiên là gì?


1
Xin chào Jack, cảm ơn phản hồi của bạn, thời gian thực hiện chậm hơn theo thứ tự, nhưng tôi muốn biết đó là sự khác biệt nếu có ...
nanounanue

Uhhh ... bạn được chào đón. Vì vậy, bạn đã thử điểm chuẩn các phương pháp khác nhau?

Cũng có nhiều cách nhanh hơn nhiều. Tất cả phụ thuộc vào yêu cầu của bạn và những gì bạn phải làm việc với. Bạn có cần chính xác 1000 hàng? Bảng có id số không? Không có / vài / nhiều khoảng trống? Tốc độ quan trọng như thế nào? Có bao nhiêu yêu cầu cho mỗi đơn vị thời gian? Có phải mọi yêu cầu đều cần một tập hợp khác nhau hoặc chúng có thể giống nhau cho một lát thời gian xác định không?
Erwin Brandstetter

6
Tùy chọn đầu tiên "(ngẫu nhiên () <0,01)" không chính xác về mặt toán học vì bạn không thể nhận được hàng nào trong phản hồi nếu không có số ngẫu nhiên nào dưới 0,01, điều đó có thể xảy ra trong mọi trường hợp (dù ít có khả năng), cho dù bảng có lớn đến đâu hoặc cao hơn ngưỡng. Tùy chọn thứ hai luôn luôn đúng
Herme

1
Nếu bạn muốn chọn chỉ một hàng, hãy xem câu hỏi này: stackoverflow.com/q/5297394/247696
Flimm

Câu trả lời:


230

Đưa ra thông số kỹ thuật của bạn (cộng với thông tin bổ sung trong các ý kiến),

  • Bạn có một cột ID số (số nguyên) chỉ có một vài khoảng trống (hoặc ít vừa phải).
  • Rõ ràng không có hoặc ít hoạt động viết.
  • Cột ID của bạn phải được lập chỉ mục! Một khóa chính phục vụ độc đáo.

Truy vấn dưới đây không cần quét tuần tự của bảng lớn, chỉ cần quét chỉ mục.

Đầu tiên, lấy ước tính cho truy vấn chính:

SELECT count(*) AS ct              -- optional
     , min(id)  AS min_id
     , max(id)  AS max_id
     , max(id) - min(id) AS id_span
FROM   big;

Phần đắt nhất có thể là count(*)(đối với các bảng lớn). Đưa ra các thông số kỹ thuật trên, bạn không cần nó. Một ước tính sẽ làm tốt, có sẵn mà hầu như không mất phí ( giải thích chi tiết ở đây ):

SELECT reltuples AS ct FROM pg_class WHERE oid = 'schema_name.big'::regclass;

Chừng nào ctkhông phải là nhiều nhỏ hơn id_span, truy vấn sẽ tốt hơn các phương pháp khác.

WITH params AS (
    SELECT 1       AS min_id           -- minimum id <= current min id
         , 5100000 AS id_span          -- rounded up. (max_id - min_id + buffer)
    )
SELECT *
FROM  (
    SELECT p.min_id + trunc(random() * p.id_span)::integer AS id
    FROM   params p
          ,generate_series(1, 1100) g  -- 1000 + buffer
    GROUP  BY 1                        -- trim duplicates
    ) r
JOIN   big USING (id)
LIMIT  1000;                           -- trim surplus
  • Tạo số ngẫu nhiên trong idkhông gian. Bạn có "một vài khoảng trống", vì vậy hãy thêm 10% (đủ để dễ dàng che khoảng trống) vào số lượng hàng cần lấy.

  • Mỗi lần idcó thể được chọn nhiều lần một cách tình cờ (mặc dù rất khó xảy ra với một không gian id lớn), vì vậy hãy nhóm các số được tạo (hoặc sử dụng DISTINCT).

  • Tham gia ids đến bàn lớn. Điều này sẽ rất nhanh với chỉ số tại chỗ.

  • Cuối cùng cắt bớt ids dư thừa chưa được ăn bởi các bản sao và khoảng trống. Mỗi hàng có một cơ hội hoàn toàn bình đẳng được chọn.

Phiên bản ngắn

Bạn có thể đơn giản hóa truy vấn này. CTE trong truy vấn trên chỉ dành cho mục đích giáo dục:

SELECT *
FROM  (
    SELECT DISTINCT 1 + trunc(random() * 5100000)::integer AS id
    FROM   generate_series(1, 1100) g
    ) r
JOIN   big USING (id)
LIMIT  1000;

Tinh chỉnh với rCTE

Đặc biệt là nếu bạn không chắc chắn về khoảng cách và ước tính.

WITH RECURSIVE random_pick AS (
   SELECT *
   FROM  (
      SELECT 1 + trunc(random() * 5100000)::int AS id
      FROM   generate_series(1, 1030)  -- 1000 + few percent - adapt to your needs
      LIMIT  1030                      -- hint for query planner
      ) r
   JOIN   big b USING (id)             -- eliminate miss

   UNION                               -- eliminate dupe
   SELECT b.*
   FROM  (
      SELECT 1 + trunc(random() * 5100000)::int AS id
      FROM   random_pick r             -- plus 3 percent - adapt to your needs
      LIMIT  999                       -- less than 1000, hint for query planner
      ) r
   JOIN   big b USING (id)             -- eliminate miss
   )
SELECT *
FROM   random_pick
LIMIT  1000;  -- actual limit

Chúng ta có thể làm việc với một khoản thặng dư nhỏ hơn trong truy vấn cơ sở. Nếu có quá nhiều khoảng trống để chúng tôi không tìm thấy đủ hàng trong lần lặp đầu tiên, rCTE tiếp tục lặp lại với thuật ngữ đệ quy. Chúng tôi vẫn cần tương đối ít khoảng trống trong không gian ID hoặc đệ quy có thể cạn trước khi đạt đến giới hạn - hoặc chúng tôi phải bắt đầu với một bộ đệm đủ lớn, bất chấp mục đích tối ưu hóa hiệu suất.

Các bản sao được loại bỏ UNIONtrong rCTE.

Bên ngoài LIMITlàm cho CTE dừng lại ngay khi chúng ta có đủ hàng.

Truy vấn này được phác thảo cẩn thận để sử dụng chỉ mục có sẵn, tạo các hàng thực sự ngẫu nhiên và không dừng lại cho đến khi chúng tôi hoàn thành giới hạn (trừ khi đệ quy chạy khô). Có một số cạm bẫy ở đây nếu bạn sẽ viết lại nó.

Bọc thành chức năng

Để sử dụng nhiều lần với các thông số khác nhau:

CREATE OR REPLACE FUNCTION f_random_sample(_limit int = 1000, _gaps real = 1.03)
  RETURNS SETOF big AS
$func$
DECLARE
   _surplus  int := _limit * _gaps;
   _estimate int := (           -- get current estimate from system
      SELECT c.reltuples * _gaps
      FROM   pg_class c
      WHERE  c.oid = 'big'::regclass);
BEGIN

   RETURN QUERY
   WITH RECURSIVE random_pick AS (
      SELECT *
      FROM  (
         SELECT 1 + trunc(random() * _estimate)::int
         FROM   generate_series(1, _surplus) g
         LIMIT  _surplus           -- hint for query planner
         ) r (id)
      JOIN   big USING (id)        -- eliminate misses

      UNION                        -- eliminate dupes
      SELECT *
      FROM  (
         SELECT 1 + trunc(random() * _estimate)::int
         FROM   random_pick        -- just to make it recursive
         LIMIT  _limit             -- hint for query planner
         ) r (id)
      JOIN   big USING (id)        -- eliminate misses
   )
   SELECT *
   FROM   random_pick
   LIMIT  _limit;
END
$func$  LANGUAGE plpgsql VOLATILE ROWS 1000;

Gọi:

SELECT * FROM f_random_sample();
SELECT * FROM f_random_sample(500, 1.05);

Bạn thậm chí có thể làm cho cái chung này hoạt động cho bất kỳ bảng nào: Lấy tên của cột PK và bảng dưới dạng đa hình và sử dụng EXECUTE... Nhưng điều đó nằm ngoài phạm vi của câu hỏi này. Xem:

Có thể thay thế

NẾU các yêu cầu của bạn cho phép các bộ giống hệt nhau cho các cuộc gọi lặp lại (và chúng ta đang nói về các cuộc gọi lặp lại) Tôi sẽ xem xét một quan điểm cụ thể hóa . Thực hiện truy vấn trên một lần và ghi kết quả vào bảng. Người dùng có được một lựa chọn gần như ngẫu nhiên ở tốc độ sáng. Làm mới lựa chọn ngẫu nhiên của bạn trong khoảng thời gian hoặc các sự kiện bạn chọn.

Postgres 9.5 giới thiệu TABLESAMPLE SYSTEM (n)

Trong trường hợp nlà một tỷ lệ phần trăm. Hướng dẫn sử dụng:

Các BERNOULLISYSTEMphương pháp lấy mẫu từng chấp nhận một đối số duy nhất đó là phần của bảng để mẫu, biểu thị bằng tỷ lệ phần trăm giữa 0 và 100 . Đối số này có thể là bất kỳ realbiểu thức định giá nào .

Nhấn mạnh đậm của tôi. Nó rất nhanh , nhưng kết quả không chính xác ngẫu nhiên . Hướng dẫn sử dụng một lần nữa:

Các SYSTEMphương pháp là đáng kể nhanh hơn so với BERNOULLIphương pháp tỷ lệ phần trăm khi lấy mẫu nhỏ được quy định, nhưng nó có thể trở lại một mẫu ít ngẫu nhiên của bảng là kết quả của hiệu ứng phân nhóm.

Số lượng hàng trả về có thể thay đổi dữ dội. Ví dụ của chúng tôi, để có được khoảng 1000 hàng:

SELECT * FROM big TABLESAMPLE SYSTEM ((1000 * 100) / 5100000.0);

Liên quan:

Hoặc cài đặt mô-đun tsm_system_rows bổ sung để có được số lượng hàng được yêu cầu chính xác (nếu có đủ) và cho phép cú pháp thuận tiện hơn:

SELECT * FROM big TABLESAMPLE SYSTEM_ROWS(1000);

Xem câu trả lời của Evan để biết chi tiết.

Nhưng điều đó vẫn không chính xác ngẫu nhiên.


Trường hợp được xác định bảng t ? Nó nên r thay vì t ?
Luc M

1
@LucM: Nó được định nghĩa ở đây : JOIN bigtbl t, viết tắt của JOIN bigtbl AS t. tlà một bí danh bảng cho bigtbl. Mục đích của nó là rút ngắn cú pháp nhưng nó sẽ không cần thiết trong trường hợp cụ thể này. Tôi đã đơn giản hóa truy vấn trong câu trả lời của mình và thêm một phiên bản đơn giản.
Erwin Brandstetter

Mục đích của phạm vi giá trị từ Gener_series (1.1100) là gì?
Tuyệt vời-o

@ Awesome-o: Mục tiêu là lấy 1000 hàng, tôi bắt đầu với thêm 10% để bù cho một vài khoảng trống hoặc (không chắc nhưng có thể) trùng lặp các số ngẫu nhiên ... lời giải thích nằm trong câu trả lời của tôi.
Erwin Brandstetter

Erwin, tôi đã đăng một biến thể của "Có thể thay thế" của bạn: stackoverflow.com/a/23634212/430128 . Sẽ quan tâm đến suy nghĩ của bạn.
Raman

100

Bạn có thể kiểm tra và so sánh kế hoạch thực hiện của cả hai bằng cách sử dụng

EXPLAIN select * from table where random() < 0.01;
EXPLAIN select * from table order by random() limit 1000;

Một thử nghiệm nhanh trên bảng lớn 1 cho thấy, người ORDER BYđầu tiên sắp xếp bảng hoàn chỉnh và sau đó chọn 1000 mục đầu tiên. Sắp xếp một bảng lớn không chỉ đọc bảng đó mà còn liên quan đến việc đọc và ghi các tệp tạm thời. Các where random() < 0.1chỉ quét các bảng đầy đủ một lần.

Đối với các bảng lớn, điều này có thể không như bạn muốn vì ngay cả một lần quét bảng hoàn chỉnh có thể mất nhiều thời gian.

Một đề xuất thứ ba sẽ là

select * from table where random() < 0.01 limit 1000;

Điều này dừng quét bảng ngay sau khi 1000 hàng được tìm thấy và do đó trả về sớm hơn. Tất nhiên điều này làm giảm sự ngẫu nhiên một chút, nhưng có lẽ điều này là đủ tốt trong trường hợp của bạn.

Chỉnh sửa: Bên cạnh những cân nhắc này, bạn có thể kiểm tra các câu hỏi đã được hỏi cho việc này. Sử dụng truy vấn [postgresql] randomtrả về khá nhiều lần truy cập.

Và một bài viết liên kết của depez phác thảo một số cách tiếp cận khác:


1 "lớn" như trong "bảng hoàn chỉnh sẽ không vừa với bộ nhớ".


1
Điểm tốt về việc viết các tập tin tạm thời để thực hiện đặt hàng. Đó thực sự là một hit lớn. Tôi đoán chúng ta có thể làm random() < 0.02và sau đó xáo trộn danh sách đó, sau đó limit 1000! Các loại sẽ ít tốn kém hơn trên một vài nghìn hàng (lol).
Thợ mỏ Donald

"Chọn * từ bảng trong đó ngẫu nhiên () <0,05 giới hạn 500;" là một trong những phương pháp dễ dàng hơn cho postgresql. Chúng tôi đã sử dụng điều này trong một trong các dự án của chúng tôi, nơi chúng tôi cần chọn 5% kết quả và không quá 500 hàng mỗi lần để xử lý.
tgharold

Tại sao trên thế giới bạn có bao giờ xem xét quét toàn bộ O (n) để lấy mẫu trên bảng hàng 500m? Nó chậm một cách lố bịch trên những chiếc bàn lớn và hoàn toàn không cần thiết.
mafu

75

thứ tự postgresql theo ngẫu nhiên (), chọn các hàng theo thứ tự ngẫu nhiên:

select your_columns from your_table ORDER BY random()

thứ tự postgresql theo ngẫu nhiên () với sự khác biệt:

select * from 
  (select distinct your_columns from your_table) table_alias
ORDER BY random()

thứ tự postgresql theo giới hạn ngẫu nhiên một hàng:

select your_columns from your_table ORDER BY random() limit 1

1
select your_columns from your_table ORDER BY random() limit 1mất ~ 2 phút để exec trên các hàng 45mil
nguyên

Có cách nào để tăng tốc độ này không?
CpILL

43

Bắt đầu với PostgreQuery 9.5, có một cú pháp mới dành riêng để nhận các phần tử ngẫu nhiên từ một bảng:

SELECT * FROM mytable TABLESAMPLE SYSTEM (5);

Ví dụ này sẽ cung cấp cho bạn 5% các yếu tố từ mytable.

Xem thêm lời giải thích về bài đăng trên blog này: http://www.postgresql.org/docs/civerse/static/sql-select.html


3
Một lưu ý quan trọng từ các tài liệu: "Phương thức HỆ THỐNG thực hiện lấy mẫu ở cấp độ khối với mỗi khối có cơ hội được chọn cụ thể; tất cả các hàng trong mỗi khối được chọn đều được trả về. Phương thức HỆ THỐNG nhanh hơn đáng kể so với phương pháp BERNOULLI khi tỷ lệ lấy mẫu nhỏ được chỉ định, nhưng nó có thể trả về một mẫu ít ngẫu nhiên của bảng do kết quả của các hiệu ứng phân cụm. "
Tim

1
Có cách nào để chỉ định một số hàng thay vì tỷ lệ phần trăm không?
Flimm

4
Bạn có thể sử dụng TABLESAMPLE SYSTEM_ROWS(400)để lấy mẫu 400 hàng ngẫu nhiên. Bạn cần phải bật các built-in tsm_system_rowsmở rộng để sử dụng tuyên bố này.
Mickaël Le Baillif

tiếc là không hoạt động với xóa.
Gadelkareem

27

Người có thứ tự BY sẽ là người chậm hơn.

select * from table where random() < 0.01;đi ghi lại bằng bản ghi và quyết định lọc ngẫu nhiên hay không. Điều này sẽ được O(N)bởi vì nó chỉ cần kiểm tra mỗi bản ghi một lần.

select * from table order by random() limit 1000;sẽ sắp xếp toàn bộ bảng, sau đó chọn 1000 đầu tiên. Bên cạnh bất kỳ phép thuật tà thuật nào đằng sau hậu trường, thứ tự là O(N * log N).

Nhược điểm của random() < 0.01nó là bạn sẽ nhận được một số lượng hồ sơ đầu ra khác nhau.


Lưu ý, có một cách tốt hơn để xáo trộn một tập hợp dữ liệu hơn là sắp xếp ngẫu nhiên: Shuffle Fisher-Yates , chạy trong O(N). Tuy nhiên, việc triển khai shuffle trong SQL nghe có vẻ khá khó khăn.


3
Không có lý do gì bạn không thể thêm Giới hạn 1 vào cuối ví dụ đầu tiên của mình. Vấn đề duy nhất là có một tiềm năng mà bạn không nhận được hồ sơ, vì vậy bạn phải xem xét điều đó trong mã của mình.
Tương đương

Vấn đề với Fisher-Yates là bạn cần phải có toàn bộ dữ liệu trong bộ nhớ để chọn từ nó. Không khả thi đối với các bộ dữ liệu rất lớn :(
CpILL

16

Đây là một quyết định phù hợp với tôi. Tôi đoán nó rất đơn giản để hiểu và thực hiện.

SELECT 
  field_1, 
  field_2, 
  field_2, 
  random() as ordering
FROM 
  big_table
WHERE 
  some_conditions
ORDER BY
  ordering 
LIMIT 1000;

6
Tôi nghĩ rằng giải pháp này hoạt động như là ORDER BY random()hoạt động nhưng có thể không hiệu quả khi làm việc với một bảng lớn.
Anh Cao

15
select * from table order by random() limit 1000;

Nếu bạn biết có bao nhiêu hàng bạn muốn, hãy kiểm tra tsm_system_rows.

tsm_system_row

mô-đun cung cấp phương thức lấy mẫu bảng HỆ THỐNG_PHẦN, có thể được sử dụng trong mệnh đề TABLESAMPLE của lệnh SELECT.

Phương pháp lấy mẫu bảng này chấp nhận một đối số nguyên duy nhất là số lượng hàng tối đa để đọc. Mẫu kết quả sẽ luôn chứa chính xác nhiều hàng đó, trừ khi bảng không chứa đủ các hàng, trong trường hợp đó toàn bộ bảng được chọn. Giống như phương pháp lấy mẫu HỆ THỐNG tích hợp, HỆ THỐNG_PHẦN thực hiện lấy mẫu ở cấp độ khối, do đó mẫu không hoàn toàn ngẫu nhiên nhưng có thể phải chịu hiệu ứng phân cụm, đặc biệt nếu chỉ yêu cầu một số lượng nhỏ hàng.

Đầu tiên cài đặt tiện ích mở rộng

CREATE EXTENSION tsm_system_rows;

Sau đó, truy vấn của bạn,

SELECT *
FROM table
TABLESAMPLE SYSTEM_ROWS(1000);

2
Tôi đã thêm một liên kết đến câu trả lời bổ sung của bạn, đó là một cải tiến đáng chú ý so với SYSTEMphương pháp tích hợp sẵn.
Erwin Brandstetter

Tôi vừa trả lời một câu hỏi ở đây (ngẫu nhiên hồ sơ duy nhất) trong thời gian đó tôi thực hiện đáng kể điểm chuẩn và thử nghiệm của tsm_system_rowstsm_system_timephần mở rộng. Theo như tôi có thể thấy, chúng hầu như vô dụng đối với bất cứ thứ gì ngoại trừ việc lựa chọn các hàng ngẫu nhiên hoàn toàn tối thiểu . Tôi sẽ biết ơn nếu bạn có thể xem nhanh và nhận xét về tính hợp lệ hoặc mặt khác của phân tích của tôi.
Vérace

6

Nếu bạn chỉ muốn một hàng, bạn có thể sử dụng một tính toán offsetxuất phát từ count.

select * from table_name limit 1
offset floor(random() * (select count(*) from table_name));

2

Một biến thể của quan điểm cụ thể hóa "Có thể thay thế" được phác thảo bởi Erwin Brandstetter là có thể.

Ví dụ, giả sử rằng bạn không muốn trùng lặp trong các giá trị ngẫu nhiên được trả về. Vì vậy, bạn sẽ cần đặt giá trị boolean trên bảng chính chứa bộ giá trị (không ngẫu nhiên) của bạn.

Giả sử đây là bảng đầu vào:

id_values  id  |   used
           ----+--------
           1   |   FALSE
           2   |   FALSE
           3   |   FALSE
           4   |   FALSE
           5   |   FALSE
           ...

Đặt ID_VALUESbàn khi cần thiết. Sau đó, như được mô tả bởi Erwin, tạo một khung nhìn cụ thể hóa ngẫu nhiên ID_VALUESbảng một lần:

CREATE MATERIALIZED VIEW id_values_randomized AS
  SELECT id
  FROM id_values
  ORDER BY random();

Lưu ý rằng chế độ xem cụ thể hóa không chứa cột được sử dụng, vì điều này sẽ nhanh chóng trở nên lỗi thời. Chế độ xem cũng không cần chứa các cột khác có thể có trong id_valuesbảng.

Để có được (và "tiêu thụ") các giá trị ngẫu nhiên, hãy sử dụng CẬP NHẬT-RETURNING trên id_values, chọn id_valuestừ id_values_randomizedtham gia và áp dụng các tiêu chí mong muốn để chỉ nhận được các khả năng có liên quan. Ví dụ:

UPDATE id_values
SET used = TRUE
WHERE id_values.id IN 
  (SELECT i.id
    FROM id_values_randomized r INNER JOIN id_values i ON i.id = r.id
    WHERE (NOT i.used)
    LIMIT 5)
RETURNING id;

Thay đổi LIMITkhi cần thiết - nếu bạn chỉ cần một giá trị ngẫu nhiên tại một thời điểm, hãy đổi LIMITthành 1.

Với các chỉ mục thích hợp trên id_values, tôi tin rằng CẬP NHẬT-RETURNING sẽ thực hiện rất nhanh với ít tải. Nó trả về các giá trị ngẫu nhiên với một chuyến đi khứ hồi cơ sở dữ liệu. Các tiêu chí cho các hàng "đủ điều kiện" có thể phức tạp theo yêu cầu. Các hàng mới có thể được thêm vào id_valuesbảng bất cứ lúc nào và chúng sẽ có thể truy cập được vào ứng dụng ngay khi chế độ xem được vật chất hóa (có thể chạy trong thời gian thấp điểm). Việc tạo và làm mới khung nhìn cụ thể hóa sẽ chậm, nhưng nó chỉ cần được thực thi khi id mới được thêm vào id_valuesbảng.


rất thú vị. Nó có hoạt động không nếu tôi không chỉ cần chọn mà còn cập nhật bằng select..cho cập nhật với pg_try_advisory_xact_lock? (tức là tôi cần nhiều lần đọc VÀ viết đồng thời)
Mathieu

1

Một bài học từ kinh nghiệm của tôi:

offset floor(random() * N) limit 1không nhanh hơn order by random() limit 1.

Tôi nghĩ offsetcách tiếp cận sẽ nhanh hơn vì nó sẽ tiết kiệm thời gian sắp xếp trong Postgres. Hóa ra là không phải.


0

Thêm một cột được gọi rvới loại serial. Chỉ số r.

Giả sử chúng ta có 200.000 hàng, chúng ta sẽ tạo một số ngẫu nhiên n, trong đó 0 n<< = 200, 000.

Chọn hàng với r > n, sắp xếp chúng ASCvà chọn hàng nhỏ nhất.

Mã số:

select * from YOUR_TABLE 
where r > (
    select (
        select reltuples::bigint AS estimate
        from   pg_class
        where  oid = 'public.YOUR_TABLE'::regclass) * random()
    )
order by r asc limit(1);

Mã này là tự giải thích. Truy vấn con ở giữa được sử dụng để nhanh chóng ước tính số lượng hàng của bảng từ https://stackoverflow.com/a/7945274/1271094 .

Ở cấp độ ứng dụng, bạn cần thực hiện lại câu lệnh nếu n> số lượng hàng hoặc cần chọn nhiều hàng.


Tôi thích điều này bởi vì nó ngắn và thanh lịch :) Và tôi thậm chí đã tìm ra cách để cải thiện nó: GIẢI THÍCH ANALYZE nói với tôi rằng như thế này, chỉ số PKEY sẽ không được sử dụng vì ngẫu nhiên () trả lại gấp đôi, trong khi PKEY cần LỚN.
fxtentacle

chọn * từ YOU_TABLE trong đó r> (select (select reltuples :: bigint AS ước tính từ pg_group trong đó oid = 'public.YOUR_TABLE' :: reggroup) * Random ()) :: thứ tự BIGINT theo r giới hạn asc (1);
fxtentacle

0

Tôi biết tôi đến bữa tiệc muộn một chút, nhưng tôi chỉ tìm thấy công cụ tuyệt vời này có tên pg_sample :

pg_sample - trích xuất một tập dữ liệu mẫu nhỏ từ cơ sở dữ liệu PostgreQuery lớn hơn trong khi vẫn duy trì tính toàn vẹn tham chiếu.

Tôi đã thử điều này với cơ sở dữ liệu hàng 350 triệu và nó thực sự nhanh, không biết về tính ngẫu nhiên .

./pg_sample --limit="small_table = *" --limit="large_table = 100000" -U postgres source_db | psql -U postgres target_db
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.