我一直在网上研究如何在大表上随机选择一行,我发现了各种结果,但后来我分析了我的数据,发现对我来说最好的方法是计算行数,并随机选择一个带有LIMIT
的行
在测试时,我开始想知道为什么这会起作用:
SET @t = CEIL(RAND()*(SELECT MAX(id) FROM logo));
SELECT id
FROM logo
WHERE
current_status_id=29 AND
logo_type_id=4 AND
active='y' AND
id>=@t
ORDER BY id
LIMIT 1;
并给出随机结果,但这总是返回相同的4或5个结果?
SELECT id
FROM logo
WHERE
current_status_id=29 AND
logo_type_id=4 AND
active='y' AND
id>=CEIL(RAND()*(SELECT MAX(id) FROM logo))
ORDER BY id
LIMIT 1;
该表有许多字段(几乎100个)和相当多的索引。超过1400万条记录和计数。当我随机选择一个时,我几乎从不需要从表中选择它,我总是需要根据不同的字段值(所有索引)进行选择。
这可能是我的MySQL服务器版本(5.6.13-log Source distribution
)的错误吗?
一种可能性是文档中的以下语句:
每次执行WHERE时,都会重新评估WHERE子句中的RAND()。
这并不总是真的。当你这样做的时候,这是真的:
where rand() < 0.01
以获得大约1%的行样本。也许MySQL优化器会说这样的话:"哦,我会评估子查询以返回一个值。为了更高效,我会在定义常量之前将该行乘以rand()
。"
如果非要我猜的话,那就是事实。
另一种可能性是,数据的排列方式使您要查找的值有一行id较大。或者,可能是有很多行在一开始就有较小的id,然后有很大的间隙。
顺便说一句,当你进行筛选时,你获得随机行的方法并不能保证返回结果。我不知道这对你来说是否重要。
编辑:
检查此版本是否如您所期望的那样工作:
SELECT id
FROM logo cross join
(SELECT MAX(id) as maxid FROM logo) c
WHERE current_status_id = 29 AND
logo_type_id = 4 AND
active = 'y' AND
id >= RAND() * maxid
ORDER BY id
LIMIT 1;
如果是这样的话,问题是正在计算最大id,然后在开始执行查询时需要额外的步骤将其乘以rand()
。