Đư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.
Trong trường hợp nlà một tỷ lệ phần trăm. Hướng dẫn sử dụng:
  Các BERNOULLIvà SYSTEMphươ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.