Làm thế nào để lấy các bản ghi ngẫu nhiên từ cơ sở dữ liệu oracle?


82

Tôi cần chọn các hàng ngẫu nhiên từ Oracle DB.

Ví dụ: Giả sử một bảng có 100 hàng, làm cách nào để tôi có thể trả về ngẫu nhiên 20 bản ghi đó từ toàn bộ 100 hàng.

Câu trả lời:


111
SELECT *
FROM   (
    SELECT *
    FROM   table
    ORDER BY DBMS_RANDOM.RANDOM)
WHERE  rownum < 21;

1
Đánh bại tôi với nó. Tuy nhiên, điều này sẽ chỉ chọn 20 hàng đầu tiên từ bảng và sắp xếp chúng ngẫu nhiên.
Nishant Sharma

10
Bạn phải biết rằng đây là một thao tác rất nặng trên các bảng lớn, vì trước tiên nó sẽ gán một số ngẫu nhiên cho MỖI hàng, sau đó sắp xếp theo giá trị này và sau đó lấy một số bản ghi từ nó.
Roeland Van Heddegem

11
@NishantSharma, các hàng được sắp xếp ngẫu nhiên, sau đó có giới hạn - nhận xét của bạn không đúng.
Simon MᶜKenzie

5
Cách tiếp cận này RẤT chậm
Evan Kroske

1
@JonBetts, tôi nghĩ rằng mẫu đó nhanh hơn và tiết kiệm tài nguyên hơn nhiều: stackoverflow.com/a/9920431/156787
Evan Kroske

50

SAMPLE () không được đảm bảo cung cấp cho bạn chính xác 20 hàng, nhưng có thể phù hợp (và có thể hoạt động tốt hơn đáng kể so với truy vấn đầy đủ + sắp xếp theo ngẫu nhiên cho các bảng lớn):

SELECT *
FROM   table SAMPLE(20);

Lưu ý: 20đây là tỷ lệ phần trăm gần đúng, không phải số hàng mong muốn. Trong trường hợp này, vì bạn có 100 hàng, nên để có được khoảng 20 hàng, bạn yêu cầu mẫu 20%.


1
mẫu nhanh nhưng không xuất hiện rất ngẫu nhiên. các bản ghi về đầu / đầu bảng có xu hướng được ưu tiên.
craigrs84

1
điều đó sẽ xảy ra nếu bạn dừng truy vấn trước khi nó đi qua toàn bộ bảng.
Jeffrey Kemp

2
Xin lỗi, tôi đã làm sai, bài viết của bạn vẫn ổn và kết quả được phân bổ đều. Đó là khi bạn thêm "where rownum <= 20" kết hợp với mẫu (20), dữ liệu bắt đầu trở nên ít ngẫu nhiên hơn.
craigrs84

13
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;

Điều này hiệu quả hơn vì nó không cần phải sắp xếp Bảng.


7
Việc dừng mẫu sau 20 hàng sẽ dẫn đến kết quả không ngẫu nhiên (các hàng được tìm thấy trước đó trong bảng sẽ được trả về thường xuyên hơn nhiều so với các hàng muộn hơn). Ngoài ra, điều này không được đảm bảo trả về 20 hàng.
Jeffrey Kemp

10
SELECT column FROM
( SELECT column, dbms_random.value FROM table ORDER BY 2 )
where rownum <= 20;

4

Để chọn ngẫu nhiên 20 hàng, tôi nghĩ tốt hơn hết bạn nên chọn rất nhiều trong số chúng được sắp xếp ngẫu nhiên và chọn 20 hàng đầu tiên của bộ đó.

Cái gì đó như:

Select *
  from (select *
          from table
         order by dbms_random.value) -- you can also use DBMS_RANDOM.RANDOM
 where rownum < 21;

Tốt nhất được sử dụng cho các bảng nhỏ để tránh chọn các khối dữ liệu lớn chỉ để loại bỏ hầu hết.


3

Tóm lại, hai cách đã được giới thiệu

1) using order by DBMS_RANDOM.VALUE clause
2) using sample([%]) function

Cách đầu tiên có lợi thế trong 'CORRECTNESS' có nghĩa là bạn sẽ không bao giờ nhận được kết quả nếu nó thực sự tồn tại, trong khi theo cách thứ hai, bạn có thể không nhận được kết quả mặc dù nó có các trường hợp thỏa mãn điều kiện truy vấn vì thông tin bị giảm trong quá trình lấy mẫu.

Cách thứ hai có lợi thế về 'HIỆU QUẢ' có nghĩa là bạn sẽ nhận được kết quả nhanh hơn và tải nhẹ cho cơ sở dữ liệu của bạn. Tôi đã nhận được một cảnh báo từ DBA rằng truy vấn của tôi bằng cách đầu tiên cung cấp tải cho cơ sở dữ liệu

Bạn có thể chọn một trong hai cách tùy theo sở thích của mình!


1

Trong trường hợp các bảng lớn, cách sắp xếp theo dbms_random.value không hiệu quả vì bạn cần quét toàn bộ bảng và dbms_random.value là chức năng khá chậm và yêu cầu chuyển đổi ngữ cảnh. Đối với những trường hợp như vậy, có 3 phương pháp bổ sung:


1: Sử dụng samplemệnh đề:

ví dụ:

select *
from s1 sample block(1)
order by dbms_random.value
fetch first 1 rows only

tức là lấy 1% của tất cả các khối, sau đó sắp xếp chúng ngẫu nhiên và chỉ trả về 1 hàng.


2: nếu bạn có chỉ mục / khóa chính trên cột có phân phối chuẩn , bạn có thể nhận giá trị tối thiểu và tối đa, nhận giá trị ngẫu nhiên trong phạm vi này và nhận hàng đầu tiên có giá trị lớn hơn hoặc bằng giá trị được tạo ngẫu nhiên đó.

Thí dụ:

--big table with 1 mln rows with primary key on ID with normal distribution:
Create table s1(id primary key,padding) as 
   select level, rpad('x',100,'x')
   from dual 
   connect by level<=1e6;

select *
from s1 
where id>=(select 
              dbms_random.value(
                 (select min(id) from s1),
                 (select max(id) from s1) 
              )
           from dual)
order by id
fetch first 1 rows only;

3: lấy khối bảng ngẫu nhiên, tạo rowid và lấy hàng từ bảng bởi rowid này :

select * 
from s1
where rowid = (
   select
      DBMS_ROWID.ROWID_CREATE (
         1, 
         objd,
         file#,
         block#,
         1) 
   from    
      (
      select/*+ rule */ file#,block#,objd
      from v$bh b
      where b.objd in (select o.data_object_id from user_objects o where object_name='S1' /* table_name */)
      order by dbms_random.value
      fetch first 1 rows only
      )
);

0

Đây là cách chọn một mẫu ngẫu nhiên từ mỗi nhóm:

SELECT GROUPING_COLUMN, 
       MIN (COLUMN_NAME) KEEP (DENSE_RANK FIRST ORDER BY DBMS_RANDOM.VALUE) 
         AS RANDOM_SAMPLE
FROM TABLE_NAME
GROUP BY GROUPING_COLUMN
ORDER BY GROUPING_COLUMN;

Tôi không chắc nó hiệu quả như thế nào, nhưng nếu bạn có nhiều danh mục và tiểu mục, điều này có vẻ hoạt động tốt.


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.