一、连续记录优化
先得到表的最大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
踩
分享到:
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到底有什么作用呀?