搜索最佳解决方案(从表格顺序中选择*由rand()限制40)运行得更快

时间:2014-01-09 09:05:46

标签: mysql sql

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行记录。

2 个答案:

答案 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;