74 votes

Sélectionner un échantillon aléatoire de résultats à partir d'un résultat de requête

Cette question demande comment obtenir un échantillon aléatoire d'enregistrements sur le serveur SQL et la réponse était d'utiliser TABLESAMPLE . Existe-t-il un équivalent dans Oracle 10 ?

Si ce n'est pas le cas, existe-t-il un moyen standard d'obtenir un échantillon aléatoire de résultats à partir d'un ensemble de requêtes ? Par exemple, comment obtenir 1 000 lignes aléatoires à partir d'une requête qui renvoie normalement des millions de résultats ?

89voto

Quassnoi Points 191041
SELECT  *
FROM    (
        SELECT  *
        FROM    mytable
        ORDER BY
                dbms_random.value
        )
WHERE rownum <= 1000

19 votes

DBMS_RANDOM est un PL/SQL, et il n'existe pas de méthode purement SQL dans Oracle pour générer des nombres aléatoires. Je vous salue pour le changement de contexte.

0 votes

Sur une table de 40'000 lignes, cette requête prend 0.1 seconde, alors qu'une requête basée sur l'utilisation de l'outil de gestion de la qualité de l'information de l'entreprise (GIS) ne prend qu'une seconde. SAMPLE(n) prend 0,02 seconde (5 fois plus vite). Donc pour ma quantité de données, ce n'est pas si lent...

78voto

grokster Points 1179

Le site Clause type vous donnera un pourcentage d'échantillon aléatoire de toutes les lignes d'un tableau.

Par exemple, ici, nous obtenons 25% des rangs :

SELECT * FROM emp SAMPLE(25)

Le SQL suivant (utilisant l'une des fonctions analytiques) vous donnera un échantillon aléatoire d'un nombre spécifique de chaque occurrence d'une valeur particulière (similaire à un GROUP BY) dans une table.

Ici, nous en échantillonnons 10 de chaque :

SELECT * FROM (
SELECT job, sal, ROW_NUMBER()
OVER (
PARTITION BY job ORDER BY job
) SampleCount FROM emp
)
WHERE SampleCount <= 10

3 votes

La plupart du temps, nous n'obtenons pas 25 % des rangs. Au lieu de cela, nous obtenons un nombre incertain de lignes. Et chaque ligne de notre ensemble original a la même chance (¼ ici) d'être sélectionnée.

3 votes

Le site SEED(n) vous permet d'obtenir toujours le même échantillon, donc le même nombre de lignes (ceci peut être utile lorsque vous avez besoin de résultats reproductibles), par ex. SELECT * from emp SAMPLE(25) SEED(1) .

0 votes

En utilisant une table avec 40'000 lignes et SAMPLE(25) J'ai vu 24,41% à 25,36% d'enregistrements retournés.

17voto

Arturo Hernandez Points 485

Ce n'est pas une réponse parfaite mais vous obtiendrez de bien meilleures performances.

SELECT  *
FROM    (
    SELECT  *
    FROM    mytable sample (0.01)
    ORDER BY
            dbms_random.value
    )
WHERE rownum <= 1000

L'échantillon vous donnera un pourcentage de votre tableau actuel, si vous voulez vraiment 1000 lignes, vous devrez ajuster ce nombre. Le plus souvent, j'ai juste besoin d'un nombre arbitraire de lignes de toute façon, donc je ne limite pas mes résultats. Sur ma base de données de 2 millions de lignes, j'obtiens 2 secondes contre 60 secondes.

select * from mytable sample (0.01)

3 votes

Si l'échantillon doit être statistiquement non biaisé, ce n'est pas une bonne approche. Comme le résultat de la requête interne est ordonné, les premières valeurs auront plus de chances d'être sélectionnées que les dernières. Imaginez à quel point il est improbable que le dernier registre de la table soit sélectionné !

0 votes

Parce que la requête interne ordonne par une valeur non indexée. La base de données doit calculer la valeur jusqu'à la dernière ligne, avant de retourner la première ligne. Parce qu'il est tout aussi probable qu'il soit choisi en premier que n'importe quel autre enregistrement.

1 votes

@Baumann : dbms_random.value est une valeur aléatoire générée par la base de données, donc les lignes ne doivent pas être considérées comme étant vraiment ordonnée (il s'agit seulement de faire en sorte que chaque ligne soit sélectionnée par SAMPLE(n) pour avoir la même probabilité d'être dans les 1000 lignes retournées).

8voto

tuinstoel Points 6329

Il existe également une clause spéciale d'échantillonnage permettant de sélectionner un pourcentage : http://oracleact.com/papers/sampleclause.html

0voto

BASMA SHAWKY Points 1

Quelque chose comme ceci devrait fonctionner :

SELECT * 
FROM table_name
WHERE primary_key IN (SELECT primary_key 
                      FROM
                      (
                        SELECT primary_key, SYS.DBMS_RANDOM.RANDOM 
                        FROM table_name 
                        ORDER BY 2
                      )
                      WHERE rownum <= 10 );

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X