`
willko
  • 浏览: 386593 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

mysql 随机获取记录 order by rand 优化

阅读更多
如果要随机获取记录数,在mysql里最简单的方法肯定是order by rand()了,但是这种方法只能在表记录极少的情况下才能使用。主要是因为order by rand()导致了using filesort.这个时候查询类型会变成all,索引会失效。只需简单的变通下,完成可以做到同样的效果。

根据记录的类型,分类连续和非连续两种。
连续指记录是连续存放的,并且有字段可以证明记录是连续的,例如自增id。
非连续是指记录是随机存放的,例如有条件的查询,结果肯定不是连续的。

一、连续记录优化
先得到表的最大id和最小id。select max(id),min(id) from table

1.在程序里随机一个在最大id和最小id的中间数,查询的时候大于这个随机数的就是随机记录了。
select * from table where id > 中间数 limit length;
缺点:如果中间数很大的话,获取不了需要的记录数,随机性不强

2.在程序里随机n个最大id和最小id的中间数,查询的时候用in获得这几个中间数的记录
select * from table where id in (中间数1, 中间数2,中间数3)
需要注意的是,如果你要获取5条记录,那建议随机10个数。
缺点:性能不如第1种方法,但是随机性更强

二、非连续记录优化
其实非连续记录的方法一样可以应用在连续记录中。
首先获得记录的总数,例如:select count(*) from table where groupid = 1;
然后在程序里随机n个小于记录总数的中间数,之后通过循环
select * from table where groupid = 1 limit 中间数,1
来获得记录。
关于优化循环sql可以采用prepare或者union all来优化循环执行

2009-3-1 添加
这两天加班,所以只有了想法,并没有去求证。
关于第三种方法利用limit达到随机的效果,我拿了点数据测试。

总记录:175,410   条件记录:20,946
order by rand
SELECT * FROM Member WHERE Country = "HK" ORDER BY RAND() limit 30

limit
SELECT * FROM Member WHERE Country = "HK" limit ?, 1

多次运行,使用order by rand胜出,limit法慢主要是因为limit偏移量大的时候。

所以,适当limit减低偏移量和增大数量可以有效提高性能,可以快过order by rand。

最后,跟大家说声对不起,没测试过就胡乱说话。

这也许只能作为其中一种思路,根据具体情况具体分析。

附上我的测试程序
$t = microtime(true);

$dbh->fetchAll('SELECT * FROM Member WHERE Country = "HK" ORDER BY RAND() limit 30');
echo microtime(true) - $t, '<br/>';

$t = microtime(true);
$count = $dbh->fetchField('SELECT COUNT(*) FROM Member WHERE Country = "HK"') / 1.5;

$sth = $dbh->prepare('SELECT * FROM Member WHERE Country = "HK" limit ?, 3') ;

for ($n = 0; $n < 10; $n++) {
	$sth->bindParam(1, mt_rand(0, $count), PDO::PARAM_INT);
	$sth->execute();
	$sth->fetchAll();
}

echo microtime(true) - $t;exit;

7
3
分享到:
评论
6 楼 zljerityzljerity 2012-10-15  
5 楼 willko 2009-03-01  
哦,对不起。有个地方说错了。

“如果你有100W条数据,你要获取99W条随机记录,那还是order by rand了。”

高效的做法是全部数据拿出来,然后随机去掉一个。。。

我不想这么咬文嚼字。。。谢谢
4 楼 willko 2009-03-01  
msnvip 写道

对于非连续性的
----
循环多次select!!我觉得要实测下性能再定 ----


呵呵,优化、缓存或者群集肯定是建立在一定基础上才有效的。如果你数据少的话,完全直接可以用order by rand,mysql的排序会很快完成。如果你有100W条数据,你要获取99W条随机记录,那还是order by rand了。。所以,优化是要在一定基础之上的,并且只提供了一种思路。
多条select和一条select从网络开销和sql初始化的角度来看是有性能差异的。

你也可以选择用存储过程一次返回结果集。
如果你使用php,那pdo的prepare方法,可以有效提高多次执行同一sql的性能,我相信php有的东西,其它语言肯定有。

第一条,网上广为传播的优化方法
第二条,我根据第一条改良的方法,已经在一个500WPV的论坛上经过了1年时间的验证。
第三条,我今天吃早餐时突然想到的,我可以保证绝对有效,using filesort的性能是低的可怕的,至于怎么利用这个思路就要看个人了。
3 楼 msnvip 2009-03-01  
对于非连续性的
----
循环多次select!!我觉得要实测下性能再定 ----
2 楼 willko 2009-03-01  
lkjust08 写道

有的明白lZ的意思select * from table where groupid = 1 limit 中间数,1中这个limit到底有什么作用呀?

抱歉,我不太会表达自己的意思。
举个例说明:

表member
member_id group_id
1         1
2         2
3         1
4         1

查询组id为1的记录,select * from member where group_id = 1;的结果是
member_id group_id
1         1
3         1
4         1

你需要从结果里随机两条记录。
首先得到记录总数 select count(*) from member where group_id = 1
结果:3
在程序里获得2个随机数,小于记录总数(也就是3)。
加入:两个随机数是0和2
那两条随机记录的sql为
select * from member where group_id = 1 limit 0,1
select * from member where group_id = 1 limit 2,1

limit offset, length的意思是:从结果的offset条记录开始,获取length数量的记录
1 楼 lkjust08 2009-03-01  
有的明白lZ的意思
select * from table where groupid = 1 limit 中间数,1中这个limit到底有什么作用呀?

相关推荐

    MYSQL随机抽取查询 MySQL Order By Rand()效率问题

    在MySQL中,直接使用`ORDER BY RAND()`对整个表进行排序,然后通过`LIMIT`获取指定数量的随机行,这种方法在大数据量时极其低效,因为它会进行全表扫描,对于每一行数据都要计算一次随机值,导致性能急剧下降。...

    SQL随机提取N条记录

    在MySQL中,可以使用RAND()函数结合ORDER BY来实现随机抽取。例如,如果你想要从表`users`中随机抽取5条记录,可以使用以下查询: ```sql SELECT * FROM users ORDER BY RAND() LIMIT 5; ``` 这将返回一个...

    MySql分组后随机获取每组一条数据的操作

    在MySQL数据库中,有时我们需要对数据进行分组处理,并从每个分组中随机选取一条记录。这在统计分析或者抽样调查等场景中非常常见。本文将详细介绍如何在MySQL中实现这一操作,以及一些关于随机选取数据的优化方法。...

    mysql优化取随机数据慢的方法

    MySQL很多时候需要获取随机数据,举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是: 代码如下:SELECT * FROM tablename ORDER BY RAND() LIMIT 1 但是,后来我查了一下MYSQL的官方手册,里面针对...

    MYSQL获取行号row_no

    - `ORDER BY RAND();`:随机排序整个结果集。 - `SELECT COUNT(*) + 1 FROM users u2 WHERE u2.userId 对每个记录计算小于当前记录ID的数量并加1,得到行号。 - `AS rowId`:将计算结果命名为`rowId`。 这种方法...

    php随机取mysql记录方法小结

    本文将介绍几种PHP随机获取MySQL记录的方法。 **方法一:Order By Rand()** 这是最常见的一种方法,通过在SQL查询语句中使用`ORDER BY RAND()`来对查询结果进行随机排序,然后利用`LIMIT`限制返回的记录数量。例如...

    MySQL 随机函数获取数据速度和效率分析

    总结来说,从MySQL中高效地随机获取数据,需要避免在`ORDER BY`子句中使用`RAND()`,而应结合表的最大和最小ID来定位随机位置。通过优化查询语句,可以在处理大数据集时显著提高性能。不过,对于特定场景,可能还...

    Mysql\学习笔记\mysql优化

    2. 使用RAND()获取随机行:`SELECT * FROM t ORDER BY RAND() LIMIT 5;` 可以随机选取表中的5行数据,但RAND()函数会导致全表扫描,对大数据量的表不建议频繁使用。 3. GROUP BY with ROLLUP:GROUP BY语句配合WITH...

    mysql获取随机数据的方法

    在MySQL中,获取随机数据是常见的需求,尤其是在测试、数据分析或者构建某些特定功能时。本文将探讨两种常用的方法,以及如何根据数据量和需求选择合适的方法。 方法一:使用`ORDER BY RAND()`函数 `ORDER BY RAND...

    MySQL随机查询记录的效率测试分析

    综上所述,优化MySQL的随机查询记录效率通常涉及避免在`ORDER BY`中使用`RAND()`,以及利用`id`字段的范围来计算随机索引。通过这样的方法,即使在大型数据集中,也能快速有效地获取随机记录,从而提高应用性能。在...

    MYSQL 随机 抽取实现方法及效率分析

    总结来说,为了在MySQL中高效地随机抽取记录,应避免使用`ORDER BY RAND()`,转而采用基于ID范围的随机数生成策略。在实践中,可以结合JOIN操作和适当调整的随机数生成逻辑,以达到更高的查询效率。在大量数据的场景...

    mysql随机抽取一定数量的记录实例讲解

    这种方法简单直观,直接在查询语句中使用`ORDER BY RAND()`对结果集进行随机排序,然后通过`LIMIT`子句限制返回的记录数量。例如: ```sql SELECT id FROM `table` ORDER BY RAND() LIMIT 1; ``` 然而,这种方法的...

    mysql随机查询若干条数据的方法

    一个15万余条的库,查询5条数据,居然要8秒以上搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据。 代码如下:SELECT * FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table...

    MySQL性能优化的最佳实践

    使用`ORDER BY RAND()`来随机排序数据是非常低效的做法。这是因为MySQL需要为每一行计算`RAND()`值,并对所有行进行排序,即使使用了`LIMIT 1`也是如此。若需要随机选择一条记录,可以考虑其他更高效的方法。 **...

Global site tag (gtag.js) - Google Analytics