ORDER BY RAND() 和大表的问题
Problems with ORDER BY RAND() and big tables
你好我今天早上问了一个问题,我发现问题不是我看的地方(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';
但我注意到“order by 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()
可能是个问题。
- 我永远不会建议在巨大的数据库中进行子查询,因为它需要很长时间执行。
- 使用正确的索引,如果需要使用内连接(切勿使用左连接)
- 如果可能,请在 php 脚本中使用您的业务逻辑,因为您的数据库可能会更大并且执行此类查询需要花费太多时间。
- 如果你只想要大型数据库中的一个数据,请不要使用
rand()
函数,取任何随机数字(1 到数据库行数)并使用限制 limit skip,number
例如。
limit 2,1
仅给出第 3 行
希望有用。
你好我今天早上问了一个问题,我发现问题不是我看的地方(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';
但我注意到“order by 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()
可能是个问题。
- 我永远不会建议在巨大的数据库中进行子查询,因为它需要很长时间执行。
- 使用正确的索引,如果需要使用内连接(切勿使用左连接)
- 如果可能,请在 php 脚本中使用您的业务逻辑,因为您的数据库可能会更大并且执行此类查询需要花费太多时间。
- 如果你只想要大型数据库中的一个数据,请不要使用
rand()
函数,取任何随机数字(1 到数据库行数)并使用限制limit skip,number
例如。limit 2,1
仅给出第 3 行 希望有用。