我想知道如何从一个小组中随机抽取一些成员,但我不知道这样做的最佳方式是什么,我认为ORDER BY RAND()
不是最佳选择,因为小组可以拥有超过100,000个会员,执行此类查询可能会非常缓慢。
我发现这种方式使用SQL,但我不知道如何在DQL中做同样的事情:How can i optimize MySQL's ORDER BY RAND() function?
答案 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语句中使用它们。
您还可以添加缓存层,将第一个查询中的键(子集)放在哪里,特别是如果您有许多记录,以避免每次都重复查询键。