ORDER BY RAND和大表的问题

问题描述

你好,我今天早上问了一个问题,我意识到问题不在我的目光(here the original question

我有这个查询,可以从通讯录中随机生成注册表。

SELECT * FROM address_book ab 
            WHERE 
            ab.source = "PB" AND 
            ab.city_id = :city_id AND 
            pb_campaign_id = :pb_campaign_id AND 
            ab.id NOT IN (SELECT address_book_id FROM calls WHERE calls.address_book_id = ab.id AND calls.status_id IN ("C","NO") OR (calls.status_id IN ("NR","OC") AND TIMESTAMPDIFF(MINUTE,calls.updated_at,NOW()) < 30))
            ORDER BY RAND()
            LIMIT 1';

但是我注意到“按rand()排序”花费了50多个时间,并且使用了大表(100k +)时最多使用25-50%的CPU,所以我在这里寻找解决方案,但没有找到任何可行的方法。 请注意: ID不是自我增加的,可能存在差距

有什么主意吗?

解决方法

我建议这样写:

SELECT *
FROM address_book ab 
WHERE ab.source = 'PB' AND 
      ab.city_id = :city_id AND 
      pb_campaign_id = :pb_campaign_id AND 
      NOT EXISTS (SELECT 1
                  FROM calls c
                  WHERE c.address_book_id = ab.id AND
                        ( c.status_id IN ('C','NO') OR
                         (c.status_id IN ('NR','OC') AND c.updated < now() - interval 30 minute)
                        ) 
                )

ORDER BY RAND()
LIMIT 1;

请注意,这会更改相关子查询中的逻辑,因此c.address_book_id = ab.id始终适用。我怀疑这是性能问题。

然后,在以下位置创建索引:

  • address_book(source,city_id,campaign_id,id)
  • calls(address_book_id,status_id,updated)

我猜想这将足以提高性能。如果碰巧有不计其数的行符合条件,那么order by rand()可能是个问题。

,
  1. 我永远不会建议大型数据库中的子查询执行时间长。
  2. 使用适当的索引,如果需要使用内部连接(从不使用左连接)
  3. 如果可能的话,请在php脚本中使用您的业务逻辑,因为可能您的数据库会更大,并且执行此类查询会花费太多时间。
  4. 如果您只希望大型数据库中的一个数据不使用rand()函数,请使用任意兰特数(1至db行数)并使用限制limit skip,number例如。 limit 2,1仅赋予第3行 希望它有用。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...