存档

文章标签 ‘随机’

MySQL的Order By Rand()有很严重的效率问题

2016年2月3日 没有评论

MySQL很多时候需要获取随机数据,举个例子,要从tablename表中随机提取一条记录,大家一般的写法就是:
SELECT * FROM tablename ORDER BY RAND() LIMIT 1

但是,后来我查了一下MYSQL的官方手册,里面针对RAND()的提示大概意思就是,在ORDER BY从句里面不能使用RAND()函数,因为这样会导致数据列被多次扫描。但是在MYSQL 3.23版本中,仍然可以通过ORDER BY RAND()来实现随机。

测试一下才发现这样效率非常低。一个15万余条的库,查询5条数据,居然要8秒以上。查看官方手册,也说rand()放在ORDER BY 子句中会被执行多次,自然效率及很低。You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times.

搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据。
SELECT *
FROM ‘table’ AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM ‘table’)) AS id) AS t2
WHERE t1.id >= t2.id
ORDER BY t1.id ASC LIMIT 5;

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

下面的语句采用的是JOIN,mysql的论坛上有人使用:
SELECT *
FROM ‘table’
WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM ‘table’ )
ORDER BY id LIMIT 1;

我测试了一下,需要0.5秒,速度也不错,但是跟上面的语句还是有很大差距。总觉有什么地方不正常。

于是我把语句改写了一下。
SELECT * FROM ‘table’
WHERE id >= (SELECT floor(RAND() * (SELECT MAX(id) FROM ‘table’)))
ORDER BY id LIMIT 1;

这下,效率又提高了,查询时间只有0.01秒。

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

完整查询语句是:
SELECT * FROM ‘table’
WHERE id >= (SELECT floor( RAND() * ((SELECT MAX(id) FROM ‘table’)-(SELECT MIN(id) FROM ‘table’)) + (SELECT MIN(id) FROM ‘table’)))
ORDER BY id LIMIT 1;

SELECT *
FROM ‘table’ 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
ORDER BY t1.id LIMIT 1;

最后在php中对这两个语句进行分别查询10次,前者花费时间 0.147433 秒,后者花费时间 0.015130 秒。看来采用JOIN的语法比直接在WHERE中使用函数效率还要高很多。

分类: mysql优化 标签: , , ,

php数组高级操作【取前几个、多维排序、随机位置插入新值】

2014年11月17日 没有评论

本文记录php的一些对数组的高级操作方法

1,取前几个

array_slice($array,0,3);//数组+起始位置+长度

———————————————————-

2,多维数组排序

比如现在有一个多维数组如下:

$array[]=array(‘paixu’=>1,’value’=>array(‘id’=>1,’title’=>’百度’));

$array[]=array(‘paixu’=>9,’value’=>array(‘id’=>2,’title’=>’腾讯’));

$array[]=array(‘paixu’=>8,’value’=>array(‘id’=>3,’title’=>’新浪’));

实际上我最终需要的数组格式是:

$resultArray=array(

array(‘id’=>1,’title’=>’百度’),

array(‘id’=>3,’title’=>’新浪’),

array(‘id’=>2,’title’=>’腾讯’)

)

即按照$array中的key为paixu来排序,代码如下:

foreach($arrayas $key=>$row) {
$paixu[$key]=$row[‘paixu’];
}
array_multisort($paixu,SORT_ASC,$array);
foreach($toplist as $key=>$row) {
$resultArray[]=$row[‘value’];
}
$resultArray为最终所得数组

———————————————————-

3,随机位置插入新数组

现在有2个数组,我希望实现的功能为:

取第一个数组的前3位聚合一个临时数组为最终数组

这个临时数组为第2个数组中随机位置插入第一个数字的后3位(循环)

实现代码如下:

$randtoplist=array(
array(‘id’=>1,’title’=>’百度’),
array(‘id’=>2,’title’=>’谷歌’),
array(‘id’=>3,’title’=>’新浪’),
array(‘id’=>4,’title’=>’网易’),
array(‘id’=>5,’title’=>’36kr’),
array(‘id’=>6,’title’=>’腾讯’),
array(‘id’=>7,’title’=>’360’)
);
$count_randtoplist=count($randtoplist);

$randtoplist_pre_three=array_slice($randtoplist,0,3);
$randtoplist_after_three=array_slice($randtoplist,3,$count_randtoplist);

//将除了$randtoplist以外的先聚合
$result=array(
array(‘id’=>11,’title’=>’google’),
array(‘id’=>12,’title’=>’apple’),
array(‘id’=>13,’title’=>’godaddy’),
array(‘id’=>14,’title’=>’新网’),
array(‘id’=>15,’title’=>’万网’),
array(‘id’=>16,’title’=>’柒帮’),
array(‘id’=>17,’title’=>’新网互联’)
);
$count_result=count($result);

//将3条以后的记录插入到$result
foreach($randtoplist_after_three as $k=>$v) {
array_splice($result,mt_rand(0,$count_result),0,array($v));
$count_result++;
}

//最后将前3条聚合,形成最终的$result
$result=array_merge($randtoplist_pre_three,$result);

分类: php学习 标签: , , ,

mysql随机读取记录order by rand()优化

2014年11月13日 没有评论

mysql随机读取记录order by rand()优化

‘SELECT id,cover,intro,tel,title,areaid,posttime,bigsortid,sortid FROM cinfos WHERE id>=(SELECT floor(RAND()*((SELECT MAX(id) FROM cinfos)-(SELECT MIN(id) FROM cinfos))+(SELECT MIN(id) FROM cinfos))) and isshow=1 ORDER BY id LIMIT 2’

分类: mysql优化 标签: , ,

php如何随机生成一个国内的IP呢

2013年9月23日 没有评论

今天由于项目需要,特意做了一个功能,php随机生成一个国内的IP地址,实现代码如下:

$ip_long = array(
array(‘607649792′,’608174079’),//36.56.0.0-36.63.255.255
array(‘1038614528′,’1039007743’),//61.232.0.0-61.237.255.255
array(‘1783627776′,’1784676351’),//106.80.0.0-106.95.255.255
array(‘2035023872′,’2035154943’),//121.76.0.0-121.77.255.255
array(‘2078801920′,’2079064063’),//123.232.0.0-123.235.255.255
array(‘-1950089216′,’-1948778497′),//139.196.0.0-139.215.255.255
array(‘-1425539072′,’-1425014785′),//171.8.0.0-171.15.255.255
array(‘-1236271104′,’-1235419137′),//182.80.0.0-182.92.255.255
array(‘-770113536′,’-768606209′),//210.25.0.0-210.47.255.255
array(‘-569376768′,’-564133889′),//222.16.0.0-222.95.255.255
);
function curl_file_get_contents($remoteUrl){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remoteUrl);
curl_setopt($ch, CURLOPT_TIMEOUT, 8);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}

$rand_key=mt_rand(0,9);
$ip=long2ip(mt_rand($ip_long[$rand_key][0],$ip_long[$rand_key][1]));
$sinaIP=json_decode(curl_file_get_contents(‘http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=’.$ip),true);
$ipcity=$sinaIP[‘province’].$sinaIP[‘city’].($sinaIP[‘isp’]?’/’.$sinaIP[‘isp’]:”);

die($ip.”<br />”.$ipcity);

由此可以生成随机的IP,并获得城市名称。

分类: php学习 标签: ,
css.php