Получить случайные записи с Doctrine - PullRequest
10 голосов
/ 17 сентября 2011

Интересно, как получить случайное количество участников из группы, но я не знаю, как лучше всего это сделать, и я думаю, что ORDER BY RAND() - не лучшая альтернатива, поскольку в группе может быть больше100 000 членов, выполнение этого типа запроса может быть очень медленным.

Я нашел этот способ использовать SQL, но я не знаю, как сделать то же самое в DQL: Как я могу оптимизировать MySQLФункция ORDER BY RAND ()?

Ответы [ 3 ]

12 голосов
/ 13 декабря 2012

Чтобы не снижать производительность, я обычно делаю следующее:

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

Конечно, объект $amount пользователей, который вы получите, является последовательным (т. Е. i-й, (i + 1)) -й, ..., (i + $amount) - th ), но обычно возникает необходимость случайного выбора одного или двух объектов, а не всего списка.Поэтому я думаю, что это эффективная альтернатива.

4 голосов
/ 22 сентября 2011

Вы можете использовать запрос, который вы нашли, чтобы эффективно извлекать идентификаторы N случайных записей через собственный запрос sql, а затем выполнить запрос доктрины, чтобы получить объекты через WHERE IN(...), используя dql.

Пример:

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

Та же стратегия применяется, если вы выбираете случайные идентификаторы из кэша (например, redis , возможно, с использованием SRANDMEMBER) - сначала выберите идентификаторы, а затем выберите сущности через WHERE IN.

Вам просто нужно убедиться, что ваши кэшированные идентификаторы синхронизированы с базой данных (удаленные идентификаторы удаляются из базы данных, из кэша и т. Д.)

0 голосов
/ 18 сентября 2011

Я не знаю ни одного способа "эффективно" заказать RAND () из Doctrine. В вашей ситуации лучше всего сначала получить первичные ключи, перетасовать эти ключи, а затем использовать их в операторе IN.

Вы также можете добавить слой кэширования, в который помещаются (подмножество) ключи из первого запроса, особенно если у вас много записей, чтобы избежать повторения запроса по ключам каждый раз.

...