Jak losowo pobierać rekordy z bazy danych Oracle?

82

Muszę losowo wybrać wiersze z bazy danych Oracle.

Przykład: Załóżmy, że tabela zawiera 100 wierszy, jak mogę losowo zwrócić 20 z tych rekordów z całych 100 wierszy.

Bhadra
źródło

Odpowiedzi:

111
SELECT *
FROM   (
    SELECT *
    FROM   table
    ORDER BY DBMS_RANDOM.RANDOM)
WHERE  rownum < 21;
cagcowboy
źródło
1
Pokonaj mnie. Spowoduje to jednak wybranie tylko pierwszych 20 wierszy z tabeli i wybranie ich losowo.
Nishant Sharma
10
Musisz mieć świadomość, że jest to bardzo ciężka operacja na dużych tabelach, ponieważ najpierw przypisze liczbę losową do KAŻDEGO wiersza, następnie sortuje według tej wartości, a następnie pobierze z niej jakieś rekordy.
Roeland Van Heddegem
11
@NishantSharma, wiersze są losowe, a następnie ograniczone - Twój komentarz nie jest poprawny.
Simon MᶜKenzie
6
To podejście jest BARDZO powolne
Evan Kroske
1
@JonBetts, myślę, że próbka jest znacznie szybsza i bardziej wydajna pod względem zasobów: stackoverflow.com/a/9920431/156787
Evan Kroske
50

SAMPLE () nie gwarantuje uzyskania dokładnie 20 wierszy, ale może być odpowiednie (i może działać znacznie lepiej niż pełne zapytanie + sortowanie losowe w przypadku dużych tabel):

SELECT *
FROM   table SAMPLE(20);

Uwaga: 20tutaj jest przybliżona wartość procentowa, a nie liczba żądanych wierszy. W tym przypadku, ponieważ masz 100 wierszy, aby uzyskać około 20 wierszy, należy poprosić o próbkę 20%.

Jeffrey Kemp
źródło
1
próbka jest szybka, ale nie wydaje się być bardzo przypadkowa. rekordy na górze / początku tabeli są zazwyczaj preferowane.
craigrs84
1
stanie się tak, jeśli zatrzymasz zapytanie, zanim przejdzie przez całą tabelę.
Jeffrey Kemp
2
Przepraszam, że popełniłem błąd, Twój post jest w porządku, a wyniki są równomiernie rozłożone. Gdy dodasz „gdzie rownum <= 20” w połączeniu z próbką (20), dane zaczną być mniej losowe.
craigrs84
14
SELECT * FROM table SAMPLE(10) WHERE ROWNUM <= 20;

Jest to bardziej wydajne, ponieważ nie wymaga sortowania tabeli.

grokster
źródło
7
Zatrzymanie próby po 20 wierszach spowoduje nielosowe wyniki (wiersze znalezione wcześniej w tabeli będą zwracane znacznie częściej niż później). Nie gwarantuje to również zwrócenia 20 wierszy.
Jeffrey Kemp
10
SELECT column FROM
( SELECT column, dbms_random.value FROM table ORDER BY 2 )
where rownum <= 20;
Bishan
źródło
4

Aby losowo wybrać 20 rzędów, myślę, że lepiej byłoby wybrać wiele z nich w losowej kolejności i wybrać pierwsze 20 z tego zestawu.

Coś jak:

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

Najlepiej używać do małych tabel, aby uniknąć wybierania dużych fragmentów danych tylko w celu odrzucenia większości z nich.

Nishant Sharma
źródło
3

Podsumowując, wprowadzono dwa sposoby

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

Pierwszy sposób ma przewagę w „PRAWIDŁOWOŚCI”, co oznacza, że ​​nigdy nie uzyskasz wyniku, jeśli faktycznie istnieje, podczas gdy drugi sposób może nie uzyskać wyniku, nawet jeśli ma przypadki spełniające warunek zapytania, ponieważ informacje są zmniejszane podczas próbkowania.

Drugi sposób ma tę zaletę, że jest „WYDAJNY”, co oznacza, że ​​szybciej uzyskasz wyniki i nie obciążysz bazy danych. Otrzymałem ostrzeżenie od DBA, że moje zapytanie przy użyciu pierwszego sposobu powoduje obciążenie bazy danych

Możesz wybrać jeden z dwóch sposobów w zależności od Twoich zainteresowań!

Jinwu Seo
źródło
1

W przypadku dużych tabel standardowy sposób sortowania według dbms_random.value nie jest skuteczny, ponieważ trzeba przeskanować całą tabelę, a dbms_random.value jest funkcją dość powolną i wymaga przełączania kontekstu. W takich przypadkach istnieją 3 dodatkowe metody:


1: sampleKlauzula użycia :

na przykład:

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

tzn. pobierz 1% wszystkich bloków, a następnie posortuj je losowo i zwróć tylko 1 wiersz.


2: jeśli masz indeks / klucz podstawowy w kolumnie z rozkładem normalnym , możesz uzyskać wartości minimalne i maksymalne, uzyskać losową wartość z tego zakresu i otrzymać pierwszy wiersz z wartością większą lub równą tej losowo wygenerowanej wartości.

Przykład:

--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: pobierz losowy blok tabeli, wygeneruj identyfikator wiersza i pobierz wiersz z tabeli według tego identyfikatora wiersza :

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
      )
);
Sayan Malakshinov
źródło
0

Oto jak wybrać losową próbkę z każdej grupy:

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;

Nie jestem pewien, jak wydajne jest to, ale jeśli masz wiele kategorii i podkategorii, wydaje się, że działa to dobrze.

SMerrill8
źródło
-1
Musimy użyć kilku zapytań, które dadzą nam losową kolumnę z

stół

Mamy stół nauczyciela

Składnia Oracle

SELECT * FROM   
(
SELECT column_name FROM table_name  
ORDER BY dbms_random.value
)  
WHERE rownum = 1;

Aby lepiej zrozumieć, wykonaj zrzut ekranu

Waseem Khan
źródło