Obtenir des enregistrements aléatoires avec la Doctrine

je me demande comment obtenir un nombre aléatoire de membres d'un groupe, mais je ne sais pas quelle est la meilleure façon de le faire, et je pense que ORDER BY RAND() n'est pas la meilleure alternative, car un groupe peut avoir plus de 100.000 membres, effectuer ce type de requête pourrait être très lent.

j'ai trouvé cette façon de faire en utilisant SQL, mais je ne sais pas comment faire la même chose dans DQL: comment optimiser L'ordre de MySQL par la fonction RAND ()?

9
demandé sur Community 2011-09-17 17:57:04

3 réponses

Je ne suis au courant d'aucune façon D'ordonner par Rand ()" efficacement " De La Doctrine. Dans votre situation, la meilleure chose est probablement d'obtenir les clés primaires d'abord, mélanger ces clés et ensuite faire usage d'eux dans une déclaration.

vous pouvez également ajouter une couche de cache où mettre (un sous-ensemble de) les clés de la première requête, surtout si vous avez beaucoup d'enregistrements, donc pour éviter de répéter la requête sur les clés à chaque fois.

0
répondu maraspin 2012-08-24 14:46:40

À ne pas réduire les performances en général, je fais comme suit:

//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();  

bien sûr, l'objet utilisateurs $amount que vous allez récupérer est consécutif (i.e. l'objet i-th, (i+1)-th,..., (i+ $amount ) - th ), mais il est généralement nécessaire de prendre une ou deux entités au hasard, pas la liste entière. Je pense donc qu'il s'agit d'une alternative efficace.

12
répondu JeanValjean 2013-01-09 09:38:12

vous pouvez utiliser la requête que vous avez trouvée afin de récupérer efficacement les ids de n enregistrements aléatoires via une requête SQL native, puis faire une requête doctrine afin de récupérer les objets via un WHERE IN(...) en utilisant dql.

exemple:

// 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) . '
');

la même stratégie s'applique si vous récupérez des identifiants aléatoires d'un cache (comme redis , peut-être en utilisant SRANDMEMBER ) - va d'abord chercher les cartes d'identité, puis va chercher la carte d'identité. entités via un WHERE IN .

vous avez juste à vous assurer que vos ID cachées sont en synchronisation avec la base de données (les ID supprimés sont supprimés de la base de données et du cache etc.)

4
répondu Max 2011-09-21 21:22:17