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

一、连续记录优化

先得到表的最大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 randSELECT * 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, '
';

$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

分享到:

18e900b8666ce6f233d25ec02f95ee59.png

72dd548719f0ace4d5f9bca64e1d7715.png

2009-02-28 16:07

浏览 24832

评论

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到底有什么作用呀?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值