2017-10-09 7 views
0

Je dois sélectionner des lignes aléatoires de ma table sql, lors de la recherche de ce cas dans google, ils ont suggéré à ORDER BY NEWID() mais il réduit les performances. Comme ma table contient plus de 2'000'000 lignes de données, cette solution ne me convient pas.Obtenir des données aléatoires de SQL Server sans impact sur les performances

J'ai essayé ce code pour obtenir des données aléatoires:

SELECT TOP 10 * 
FROM Table1 
WHERE (ABS(CAST((BINARY_CHECKSUM(*) * RAND()) AS INT)) % 100) < 10 

Il diminue également les performances parfois.

Pourriez-vous me suggérer une bonne solution pour obtenir des données aléatoires de ma table, j'ai besoin de lignes minimum de ces tables comme 30 lignes pour chaque demande. J'ai essayé TableSAMPLE pour obtenir les données, mais il ne retourne rien une fois que j'ai ajouté ma condition où il renvoie les données par la base de la page et non la base de la ligne.

+0

[Cochez cette case, je pense que cela vous aide] (https://stackoverflow.com/questions/19412/how-to-request-a-random-row-in-sql) – Dogan

+0

Votre tableau a un index unique ou une clé primaire? –

+0

Oui, il a la clé primaire avec l'index unique – Manikandan

Répondre

1

Essayez de calculer les identifiants aléatoires avant de filtrer votre grande table.
depuis votre clé n'est pas l'identité, vous devez les enregistrements numériques et cela aura une incidence sur les performances ..

Faites attention, je l'ai utilisé clause distincte pour être sûr d'obtenir des numéros

EDIT: J'ai modifié la requête d'utiliser un filtre arbitraire sur votre grande table

declare @n int = 30 

;with 
t as (
    -- EXTRACT DATA AND NUMBER ROWS 
    select *, ROW_NUMBER() over (order by YourPrimaryKey) n 
    from YourBigTable t 
    -- SOME FILTER 
    WHERE 1=1 /* <-- PUT HERE YOUR COMPLEX FILTER LOGIC */ 
), 
r as (
    -- RANDOM NUMBERS BETWEEN 1 AND COUNT(*) OF FILTERED TABLE 
    select distinct top (@n) abs(CHECKSUM(NEWID()) % n)+1 rnd 
    from sysobjects s 
    cross join (SELECT MAX(n) n FROM t) t 
) 
select t.* 
from t 
join r on r.rnd = t.n 
+0

Depuis ma table n'a pas identifiant id pour entier, j'ai utilisé Uniqueidentifier – Manikandan

+0

Nice, est-ce bon pour les grandes tables, Puisque ma table a plus de 2'000'000 lignes – Manikandan

+0

dans mes tests c'est très très rapide (250ms), aussi avec uniqueidentifier comme clé primaire, et vous pouvez l'améliorer beaucoup plus en remplaçant le COUNT (*) '@ @ max avec une fonction plus efficace et obtenir ~ 30% de moins – MtwStark

-1

Si votre clé uniqueidentifier est un GUID aléatoire (non généré avec NEWSEQUENTIALID() ou UuidCreateSequential), vous pouvez utiliser la méthode ci-dessous. Cela utilisera l'index de clé primaire en cluster sans trier toutes les lignes.

SELECT t1.* 
FROM (VALUES(
     NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()) 
    ,(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()) 
    ,(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID()),(NEWID())) AS ThirtyKeys(ID) 
CROSS APPLY(SELECT TOP (1) * FROM dbo.Table1 WHERE ID >= ThirtyKeys.ID) AS t1; 
+0

Hey ma clé primaire était nouvelle séquentielleId – Manikandan

+0

vous pouvez extraire 30 fois le même enregistrement – MtwStark

+0

et aussi vous pouvez obtenir moins de 30 enregistrements – MtwStark