简体   繁体   English

使用Doctrine获取随机记录

[英]Get random records with Doctrine

I wonder how to get a random number of Members from a Group, but I do not know what is the best way to do this, and I think ORDER BY RAND() is not the best alternative, as a Group can have more than 100,000 Members, performing this type of query could be very slow. 我想知道如何从一个集团中随机抽取一些成员,但我不知道最好的方法是什么,我认为ORDER BY RAND()不是最好的选择,因为一个集团可以拥有超过100,000执行此类查询的成员可能会非常慢。

I found this way to make using SQL, but I do not know how to do the same thing in DQL: How can i optimize MySQL's ORDER BY RAND() function? 我发现这种方式使用SQL,但我不知道如何在DQL中做同样的事情: 我如何优化MySQL的ORDER BY RAND()函数?

To not decrease performances I generally do as follows: 为了不降低性能我通常做如下:

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

Of course, the $amount users object you will retrieve are consecutive (ie the i-th, (i+1)-th,...,(i+ $amount )-th ), but usually there is the need of taking one or two entities at random, not the whole list. 当然,你要检索的$amount用户对象是连续的(即第i,第(i + 1),...,(i + $amount )-th ),但通常需要一个或两个实体随机,而不是整个列表。 Hence, I think that this is an effective alternative. 因此,我认为这是一个有效的选择。

You could use the query you found in order to efficiently retrieve the ids of N random records via a native sql query, then do a doctrine query in order to fetch the objects via a WHERE IN(...) using dql. 您可以使用您找到的查询,以便通过本机SQL查询有效地检索N个随机记录的ID,然后执行一个学说查询,以便使用dql通过WHERE IN(...)获取对象。

Example: 例:

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

The same strategy applies if you fetch random ids from a cache (like redis , maybe using SRANDMEMBER ) - first fetch the ids, then fetch the entities via a WHERE IN . 如果从缓存中获取随机ID(如redis ,可能使用SRANDMEMBER ),则应用相同的策略 - 首先获取ID,然后通过WHERE IN获取实体。

You just have to make sure your cached ids are in sync with the database (deleted ids are removed from database and from cache etc.) 您只需确保缓存的ID与数据库同步(已删除的ID将从数据库和缓存等中删除)

I'm not aware of any way to ORDER BY RAND() "efficiently" from Doctrine. 我不知道从Doctrine“有效”地订购ORDER BY RAND()。 In your situation, the best thing is probably to get primary keys first, shuffle these keys and then make use of them within an IN statement. 在您的情况下,最好的方法可能是先获取主键,然后将这些键随机化,然后在IN语句中使用它们。

You could also add a caching layer where to put (a subset of) the keys from the first query, especially if you have many records, so to avoid repeating the query on keys each time. 您还可以添加一个缓存层,从第一个查询中放置(一部分)键,特别是如果您有许多记录,这样可以避免每次都重复查询键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM