使用Doctrine获取随机记录

时间:2011-09-17 13:57:04

标签: php random doctrine-orm dql

我想知道如何从一个小组中随机抽取一些成员,但我不知道这样做的最佳方式是什么,我认为ORDER BY RAND()不是最佳选择,因为小组可以拥有超过100,000个会员,执行此类查询可能会非常缓慢。

我发现这种方式使用SQL,但我不知道如何在DQL中做同样的事情:How can i optimize MySQL's ORDER BY RAND() function?

3 个答案:

答案 0 :(得分:12)

为了不降低表现,我通常会做如下:

//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-th,(i + 1)-th,...,(i + $amount) - (),但通常需要随机选择一个或两个实体,而不是整个列表。因此,我认为这是一种有效的替代方案。

答案 1 :(得分:4)

您可以使用您找到的查询,以便通过本机SQL查询有效地检索N个随机记录的ID,然后执行一个学说查询,以便使用dql通过WHERE IN(...)获取对象。

示例:

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

如果您从缓存中获取随机ID(例如redis,可能使用SRANDMEMBER),则会采用相同的策略 - 首先获取ID,然后通过WHERE IN获取实体。< / p>

您只需要确保缓存的ID与数据库同步(已从数据库和缓存等中删除已删除的ID。)

答案 2 :(得分:0)

我不知道从Doctrine“有效”地订购ORDER BY RAND()。在您的情况下,最好的方法可能是先获取主键,然后将这些键随机化,然后在IN语句中使用它们。

您还可以添加缓存层,将第一个查询中的键(子集)放在哪里,特别是如果您有许多记录,以避免每次都重复查询键。