mysql随机查询

最近无事,翻了一下以前的博客,发现部分文章现在看起来确实有很大的差异,对于这篇mysql随机查询的文章,现在看起来,问题的确存在。

举个例子,要从tbl_consult表中随机提取一条记录,大家一般的写法就是:

select * from tbl_consult order by rand() limit 1;

执行之后用mysql slow query log看下,发现全表扫了2次,如果这个量非常大,那这说明了问题确实存在。

在官方手册里有这样说过,在order by从句里面不能使用rand()函数,因为这样会导致数据列被多次扫描,意思应该明白了吧,就是说rand()查询的时候会在全表里搜索多次,直到你取到结果数。

有集中查询方法,做一下对比。

1、采用JOIN,查询max(id) * rand()来随机获取数据

SELECT * 
FROM tbl_consult AS t1 JOIN (select round(rand() * (select max(id) FROM tbl_consult)) AS id) AS t2 
WHERE t1.id >= t2.id 
ORDER BY t1.id ASC LIMIT 1; 

但是这样会产生连续的5条记录。解决办法只能是每次查询一条,查询5次。即便如此也值得,因为15万条的表,查询只需要0.01秒不到。

2、下面这句在mysql论坛上人用到

SELECT * 
FROM tbl_consult 
WHERE id >= (select floor( max(id) * rand()) FROM tbl_consult ) 
ORDER BY id LIMIT 1;

执行上面这句发现还是会大量扫描,也不推荐。

3、稍微的改一下之后

SELECT * FROM tbl_consult 
WHERE id >= (select floor(RAND() * (select max(id) FROM tbl_consult)))  
ORDER BY id LIMIT 1; 

最后,再把语句完善一下,加上MIN(id)的判断。我在最开始测试的时候,就是因为没有加上MIN(id)的判断,结果有一半的时间总是查询到表中的前面几行。

4、完整查询语句是

SELECT * FROM tbl_consult 
WHERE id >= (select floor( RAND() * ((select max(id) FROM tbl_consult ) - (select min(id) FROM tbl_consult)) + (select min(id) FROM tbl_consult)))  
ORDER BY id LIMIT 1; 

5、再调整一下

SELECT * 
FROM tbl_consult AS t1 JOIN (select ROUND(RAND() * ((select MAX(id) FROM tbl_consult)-(select MIN(id) FROM tbl_consult))+(select MIN(id) FROM tbl_consult)) AS id) AS t2 
WHERE t1.id >= t2.id 
ORDER BY t1.id LIMIT 1;

看来采用JOIN的语法比直接在WHERE中使用函数效率还要高很多。