select * from table order by rand() limit 40
众所周知,这可以按预期工作,但需要很长时间。 所以我需要让它跑得更快。
我得到了一些解决方案,如下:
SELECT t1.* FROM talbe AS t1 JOIN
(SELECT ROUND(RAND() * ((SELECT MAX(id) FROM table)-(SELECT MIN(id) FROM table))+(SELECT MIN(id) FROM table)) AS id) AS t2
WHERE t1.id >= t2.id AND t1.type=1
ORDER BY t1.id
LIMIT 40
但它并不完全正常。 有时它无法获得40行记录。
答案 0 :(得分:2)
你明白你的第二个版本在做什么吗?
最多可选择40条记录id
大于或等于MIN(id)
和MAX(id)
之间的随机数。从某种意义上说,这个不是选择40个随机记录:它选择一个随机记录,然后选择跟随id
的39个随机记录。可以说它正在选择随机的记录簇。显然,如果随机选择的记录太接近最大值id
,则不会有39个跟随。
此外,每个群集的概率与id
一起分布 - 因此该列中任何缺乏一致性(例如,删除记录的差距)导致结果缺乏一致性。在极端情况下,假设一个人有八十条记录id
1-40和1,000,001-1,000,040。选择前四十的任何一个概率比最后四十个小百万倍(因为任何随机值> 40,例如41或2,753或999,999将仅返回1,000,000以上的记录)。
所以,如果考虑到所有这些,你很乐意继续使用第二个版本,尽管它有陷阱而不是id
和{{1之间的随机MIN(id)
选择的起始记录可以从最大值MAX(id)
和第40 id
之间选择MIN(id)
。
id
但是,如果上述方法存在上述缺陷,那么@Quassnoi的文章“Selecting random rows”(@Kay Nelson linked above)提供了更好的解决方案基于将SELECT t1.*
FROM `table` JOIN (
SELECT min.id + ROUND(RAND() * (max.id - min.id)) AS id
FROM (SELECT id FROM `table` ORDER BY id DESC LIMIT 39, 1) max,
(SELECT id FROM `table` ORDER BY id ASC LIMIT 0, 1) min
) AS pivot ON pivot.id <= table.id
WHERE table.type = 1
ORDER BY table.id
LIMIT 40
与下一个选择记录的概率进行比较。我建议添加一个RAND()
子句,以确保MySQL在找到必要数量的随机记录后停止其表扫描:
LIMIT
答案 1 :(得分:1)
MySQL提供HANDLER,让我们直接访问存储引擎。
使用HANDLER
我们可以打开某些tblle并可以来回导航。如果您正在考虑一个tblle的随机行,我认为HANDLER
是获取MySQL随机行的不错选择。
这种方法不是ANSI标准,需要自己编写更多代码,但是你正在考虑性能问题,我认为HANDLER
对你有好处。
您可以在此处http://www.sqlfiddle.com/#!2/ddf01/4进行测试。
假设您已经知道客户端在1和COUNT(*)
之间生成表和随机数的总记录数
在我的示例中,表tbl
有20条记录,我想获取随机(6,8,10,12,15)行的表。
基本用法
-- OPEN tbl
HANDLER tbl OPEN;
-- READ 6th record
HANDLER tbl READ FIRST LIMIT 5, 1;
-- READ 8th record
HANDLER tbl READ FIRST LIMIT 7, 1;
-- READ 10th record
HANDLER tbl READ FIRST LIMIT 9, 1;
HANDLER tbl READ FIRST LIMIT 11, 1;
HANDLER tbl READ FIRST LIMIT 14, 1;
HANDLER tbl CLOSE;
前面的用法很容易理解,但是有很多磁盘搜索(移动第6个位置然后先返回并移动第8个记录,依此类推)所以,下面的代码效率很高。
-- OPEN tbl
HANDLER tbl OPEN;
-- READ 6th record
HANDLER tbl READ FIRST LIMIT 5, 1;
-- and READ 8th record
HANDLER tbl READ NEXT LIMIT 1, 1;
-- and READ 10th record
HANDLER tbl READ NEXT LIMIT 1, 1;
HANDLER tbl READ NEXT LIMIT 1, 1;
HANDLER tbl READ NEXT LIMIT 2, 1;
HANDLER tbl CLOSE;