Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

SQL Server : Renvoyer les données aléatoirement Tri aléatoire ou tirage aléatoire

Comment réaliser un tri aléatoire d'une table ou récupérer de la même façon une partie seulement d'une table ?

La première hypothèse serait d'utiliser la fonction RAND() de SQL Server qui génère un nombre aléatoire compris entre 0 et 1.

SELECT *
FROM Person.Address
ORDER
BY RAND()

Même en exécutant plusieurs cette requête le résultat reste identique et non trié aléatoirement (le jeu de données est renvoyé dans l'ordre physique où il se trouve dans la base de données).

La raison est que le moteur réalise toujours une évaluation de la fonction une fois pour toute, pour la portée de la requête. Pour s'en convaincre, exécutez la variante de la requête ci-dessus :

SELECT *, RAND()
FROM Person.Address

La dernière colonne contient pour chaque enregistrement la même valeur. Plusieurs raisons à cela : conserver la consistance des données au travers de la requête, et conserver de bonnes performances. Peut de fonctions sont des exceptions à cette règles, voyons en une : NEWID()

NEWID() renvoie une valeur binaire de 16 octets générée par un générateur pseudo aléatoire. Cette valeur est belle est bien aléatoire et se veut unique (à 99,9999%), elle fait donc exception à la règle ci-dessus.

Testons notre requête avec cette variante :

SELECT *
FROM Person.Address
ORDER BY NEWID()

Le résultat est cette fois bien aléatoire et change à chaque exécution. Pour réaliser un tirage d'un certains nombres d'enregistrement par cette méthode, il faudra lui ajouter la clause TOP (à noter que les parenthèses sont optionnelles) :

SELECT TOP(1) *
FROM Person.Address
ORDER BY NEWID()

Cette méthode bien que faisant exactement ce que nous souhaitons peut se révéler gourmande en ressources dans la mesure où le moteur va être obligé de calculer un GUID pour chaque ligne dans la table, imaginez donc une table de 100 millions d'enregistrements.

SQL Server 2005 introduit une nouvelle fonction permettant de lister plus efficacement des données de manière aléatoire :

SELECT *
FROM Person.Address TABLESAMPLE(300 ROWS)

Cette fonction prend 2 types d'arguments, le nombre d'enregistrement souhaité ou le pourcentage d'enregistrements souhaités. Bien que très efficace cette fonction souffre tout de même d'un problème :

SELECT *
FROM Person.Address TABLESAMPLE(1 ROWS)

Testez cette requête plusieurs fois d'affiler et vous constaterez que de temps en temps vous aurez des résultats sous forme de plusieurs lignes, mais pas une, ou rien !

Le comportement de TABLESAMPLE est de filtrer au niveau des pages de la table (bloc de 8ko comprenant les données). Cette méthode bien que plus efficace que la notre, donne des effets surprenants, cela peut être gênant tout dépend de ce que vous souhaitez faire.

D'où l'idée de combiner les 2 :

    SELECT TOP(1)
    FROM Sales.SalesOrderDetail TABLESAMPLE(300 ROWS
    ORDER BY NEWID();

Ce qui fonctionne comme attendu… Attention le chiffres tu TABLESAMPLE est à déterminer de manière à ce qu'il renvoie toujours au moins un enregistrement, sinon la requête présente ne renverra aucuns résultats.

Et les performances dans tout çà (la table de test comprend 121000 enregistrements) ?

Requête à base de TOP et ORDER NEWID() seule :

  • 1356 pages lues
  • 249 ms de CPU consommé
  • Sur 1000 exécutions 129 s de temps d'exécution

Requête à base de TOP et ORDER NEWID() + TABLESAMPLE :

  • 3 pages lues
  • 0 ms de CPU consommé
  • Sur 1000 exécutions 750 ms de temps d'exécution

Clairement le TABLESAMPLE remporte la palme ici.

Bons tris…

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Publié samedi 7 juin 2008 23:42 par christian

Commentaires

Pas de commentaires
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- [WPF] XPSReader v0.2 par Blog Technique d'Audrey PETIT le il y a 1 heure et 35 minutes

- Entity Framework : providers Oracle, MySQL et PostgreSQL par Matthieu MEZIL le il y a 8 heures et 10 minutes

- [WPF] Nouvel article sur c2i.fr par Richard Clark le 09-06-2008, 17:33

- F# nouvelle CTP 1.9.6.2 (update) par Pierrick's Blog le 09-06-2008, 13:27

- La suite ...Proposition de collaboration rédactionnelle entre les communautés de développeurs et Microsoft France par LucasR le 09-05-2008, 17:45

- [Fun] Votre simulateur de vol avec Microsoft ESP par Julien Chable le 09-05-2008, 12:02

- [Best Practices] Customisation du My Site : Comment le modifier en amont et en aval par The Mit's Blog le 09-05-2008, 10:47

- Patrick Tisseghem s'en est allé ... par The Mit's Blog le 09-05-2008, 10:04

- MS AutoCollage par alex# le 09-05-2008, 09:18

- Un grand SharePointeur nous a quitte : Patrick Tisseghem manquera à la communauté ! par RedoBlog - The .NET Gentleman !!! le 09-05-2008, 08:52