2011-09-17 19 views
9

Zastanawiam się, jak uzyskać losową liczbę członków z grupy, ale nie wiem, jaki jest najlepszy sposób, aby to zrobić, i myślę, że ORDER BY RAND() nie jest najlepszą alternatywą, ponieważ grupa może mieć ponad 100 000 członków, wykonanie tego typu zapytania może być bardzo powolne.Otrzymuj losowe rekordy z Doctrine

znalazłem w ten sposób, aby przy użyciu SQL, ale nie wiem jak zrobić to samo w DQL: How can i optimize MySQL's ORDER BY RAND() function?

+1

Możliwy duplikat [Jak wybrać losowo z doktryną] (http://stackoverflow.com/questions/10762538/how-to-select-randomly-with-doctrine) –

Odpowiedz

0

nie jestem świadomy jakikolwiek sposób ORDER BY RAND() „skutecznie” z Doktryna. W twojej sytuacji najlepiej jest najpierw uzyskać klucze podstawowe, przetasować te klucze, a następnie użyć ich w instrukcji IN.

Można również dodać warstwę pamięci podręcznej, w której można umieścić (podzestaw) klucze z pierwszego zapytania, szczególnie w przypadku wielu rekordów, aby uniknąć powtarzania zapytania za każdym razem.

4

Można użyć znalezionego zapytania w celu wydajnego pobrania identyfikatorów N rekordów losowych za pośrednictwem natywnego zapytania SQL, a następnie wykonać zapytanie dotyczące doktryny w celu pobrania obiektów za pomocą metody WHERE IN(...) przy użyciu polecenia dql.

Przykład:

// fetch $randomIds via native sql query using $em->getConnection()->... methods 
// or from a memory based cache 

$qb = $em->createQueryBuilder('u'); 

$em->createQuery(' 
    SELECT u 
    FROM Entity\User 
    WHERE ' . $qb->expr()->in('u.id', $randomIds) . ' 
'); 

Tę samą strategię stosuje się, jeśli pobrać losowe identyfikatory z pamięci podręcznej (jak redis, może za pomocą SRANDMEMBER) - najpierw pobrać identyfikatory, a następnie pobrać podmiotów poprzez WHERE IN.

Musisz tylko upewnić się, że w pamięci podręcznej identyfikatory są zsynchronizowane z bazą danych (usunięte identyfikatory są usuwane z bazy danych oraz pamięci podręcznej, itp)

+0

Mam obserwację. Pobieranie identyfikatorów przez natywne zapytanie SQL za pomocą '$ em-> getConnection() -> ...' lub przez '$ em-> createQuery (" ... zapytanie SQL ... ") nie jest takie samo dla ty? – JeanValjean

12

nie zmniejszać występy ogólnie zrobić w następujący sposób:

//Retrieve the EntityManager first 
$em = $this->getEntityManager(); 

//Get the number of rows from your table 
$rows = $em->createQuery('SELECT COUNT(u.id) FROM AcmeUserBundle:User u')->getSingleScalarResult(); 

$offset = max(0, rand(0, $rows - $amount - 1)); 

//Get the first $amount users starting from a random point 
$query = $em->createQuery(' 
       SELECT DISTINCT u 
       FROM AcmeUserBundle:User u') 
->setMaxResults($amount) 
->setFirstResult($offset); 

$result = $query->getResult(); 

oczywiście, użytkownicy $amount obiekt będzie pobierać są rzędu (czyli I-th (i + 1) -tego, ..., (i + $amount) -ty), ale zazwyczaj istnieje potrzeba o losowaniu jednego lub dwóch podmiotów, a nie całej listy. Dlatego uważam, że jest to skuteczna alternatywa.

+0

Możesz także użyć niestandardowego numerycznego fn lub DoctrineExtensions Lib jako [alternate] (http://digitalfortress.tech/php/get-random-rows-in-doctrine/). –