我遇到了一个有趣的MySQL问题。当我尝试将RAND()函数与一个大整数相乘时,我得到的最大随机数非常小。这是我的MySQL查询,应该是一个非常快速的随机查询,但它返回ID最大36000,即使有4600000+ ID。
SET @maxID=(SELECT MAX(id) FROM property); #it's about 4600000
SELECT * FROM property
WHERE
downloaded_at IS NULL
AND id >= FLOOR(1 + RAND() * @maxID) #this returns max +/-36000
LIMIT 100
当我将此代码移动到普通SELECT查询时,一切都很好
SELECT FLOOR(1 + RAND() * (SELECT MAX(id) FROM property))
有人可以解释一下,为什么会出现这个错误?谢谢!
编辑
嗯,不知怎的,当我删除downloaded_at IS NULL
时,ID会更高,但结果不再是随机的。
我不能使用ORDER BY RAND(),因为表太大,查询太慢,整个服务器最终在几分钟内崩溃
版本是5.7.21-0ubuntu0.16.04.1
答案 0 :(得分:1)
您的随机行选择方法 偏向 ...正在选择的行的概率与其ID成正比。例如,如果你有10行id = 1到10,那么1有10%被选中的机会,2有20%等等。
此外,您的代码选择小于~36000的ID的原因显而易见:行(通常)以PK顺序处理,并且在找到第100个匹配行时,查询仅处理ID大约为36000的行。
现在,如果您有兴趣选择100个随机行,则可以改为使用此查询:
SELECT *
FROM property
WHERE id IN (
SELECT id
FROM property
WHERE downloaded_at IS NULL
ORDER BY RAND()
LIMIT 100
)
或者可能是这个(粗略轮廓):
SELECT *
FROM property
WHERE id IN (
SELECT id
FROM property
WHERE RAND() <= 100.0 / @maxID -- explanation below
LIMIT 100
)
以上内容不涉及排序,但仍需要扫描所有ID。 100.0
与所需的行数相同,但为了确保添加更多行。这应该导致每行选择的概率相等。
答案 1 :(得分:0)
问题是每次评估rand()
子句中的条件时都会调用where
。相反,将值放在子查询中:
SELECT p.*
FROM property p CROSS JOIN
(SELECT FLOOR(1 + RAND() * @maxID) as idlim) x
WHERE p.downloaded_at IS NULL AND
p.id >= x.idlim #this returns max +/-36000
LIMIT 100;
这确保了rand()
函数只被调用一次。