Newid()/order by fonctionnera, mais sera très coûteux pour les grands ensembles de résultats car il faut générer un identifiant pour chaque ligne, puis les trier.
TABLESAMPLE() est bon du point de vue des performances, mais vous obtiendrez des résultats groupés (toutes les lignes d'une page seront retournées).
Pour obtenir un échantillon aléatoire réel plus performant, le meilleur moyen est de filtrer les lignes de manière aléatoire. J'ai trouvé l'exemple de code suivant dans l'article SQL Server Books Online Limiter les ensembles de résultats en utilisant TABLESAMPLE :
Si vous voulez vraiment un échantillon aléatoire de lignes individuelles, modifiez votre requête pour filtrer les lignes de façon aléatoire, au lieu utiliser TABLESAMPLE. Par exemple, la requête requête suivante utilise la fonction NEWID pour renvoyer environ un pour cent des lignes de la table Sales.SalesOrderDetail :
SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
La colonne SalesOrderID est incluse dans l'expression l'expression CHECKSUM afin que NEWID() est évaluée une fois par ligne à afin de réaliser un échantillonnage par ligne. L'expression CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int) donne comme résultat une valeur flottante aléatoire comprise entre 0 et 1.
Lorsque je l'exécute sur une table de 1 000 000 de lignes, voici mes résultats :
SET STATISTICS TIME ON
SET STATISTICS IO ON
/* newid()
rows returned: 10000
logical reads: 3359
CPU time: 3312 ms
elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()
/* TABLESAMPLE
rows returned: 9269 (varies)
logical reads: 32
CPU time: 0 ms
elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)
/* Filter
rows returned: 9994 (varies)
logical reads: 3359
CPU time: 641 ms
elapsed time: 627 ms
*/
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
SET STATISTICS IO OFF
SET STATISTICS TIME OFF
Si vous pouvez vous en sortir en utilisant TABLESAMPLE, vous obtiendrez les meilleures performances. Sinon, utilisez la méthode newid()/filter. newid()/order by devrait être le dernier recours si vous avez un grand ensemble de résultats.
3 votes
MSDN propose un bon article qui couvre une grande partie de ces questions : Sélection aléatoire de rangs dans un grand tableau
0 votes
Duplicata possible de Comment demander une ligne aléatoire en SQL ?