大量数据存存在对比bitmap
大量数据存存在对比bitmap
这样的一个场景,数据库中大概有40万条记录,而csv文件中,大概相当于mysql中的数据+部分新增的数据。对于csv中的新记录(mysql没有的)要插入到mysql表中,如果存在,则忽略。在思考这样的脚本,崩溃的原因,执行时间长。在解决方式上:1、重复的数据让mysql来计算,使用insert ignore into,但是考虑到提交不宜过多,采用分批。(实际效果: 非常快,在数据库空的时候,12S,不为空的时候(就是重复数据不添加)的时候,只需要2S )2、在php层面上解决,一次从数据库中获取到所有主键,每次读取一行,判断是不是在数据中,如果在,忽略,最后将新增部分,分批插入。但是计算量都卡在存不存在。
关于存不存在,这个有两种算法可以优化,一个是bitmap,但是需要考虑到bit位存储的大小端问题。另外一种是布隆过滤。当然,40万没有大到那么大,所以也不一定要这样优化。
为啥40万的大数组,判断一个组件这么慢?底层是因为,数据存储的不连续?
isset判断方式
与isset相似的还有:直接拿这个数组值,empty判断等。效率大致一样。
array_key_exists大概需要两倍的时间。下面的代码,在windows是运行时间为5秒左右,linux为0.2秒左右。
<?php
/**
* 2019-12-24 15:41:32
*/
//第一种方式 关联数组
$t0 = microtime(true);
$data = [];
for($i=0;$i<400000;$i++){
$data['#'.'$i']=true;
//$data[]=$i;
}
echo (microtime(true) - $t0).PHP_EOL;
for($i=0;$i<400000;$i++){
//empty($data['#'.mt_rand(1,400000)]);
//isset($data['#'.mt_rand(1,400000)]);
@$data['#'.mt_rand(1,400000)];
}
echo (microtime(true) - $t0).PHP_EOL;
windows
$ time php test.php
0.044121980667114
5.5688560009003
real 0m6.601s
user 0m0.000s
sys 0m0.015s
Linux
chaofml@scc:~/demo$ time php set.php
0.020446062088013
0.2878589630127
real 0m0.310s
user 0m0.305s
sys 0m0.004s
in_array判断
<?php
/**
* 2019-12-24 15:41:32
*/
$t0 = microtime(true);
//第二种方式 普通数组 in_array判断
$data = [];
for($i=0;$i<400000;$i++){
$data[]=$i;
}
echo (microtime(true) - $t0).PHP_EOL;
//1万条大概4s左右,随机数本身不很耗时
for($i=0;$i<10000;$i++){
$temp = in_array(mt_rand(1,400000),$data);
//$temp = in_array(30000,$data); 固定查一个,很快,可能结果缓存了。
}
windows
$ time php test.php
0.049081087112427
real 0m3.519s
user 0m0.015s
sys 0m0.015s
linux
[root@sf104155 test]# time php test.php
0.11430096626282
real 0m45.219s
user 0m45.144s
sys 0m0.068s
chaofml@scc:~/demo$ time php set.php
0.027791976928711
real 0m3.176s
user 0m3.031s
sys 0m0.028s
总结
上述两种方式,关联数组,40万大概5秒左右,还是很慢,相当于每秒8万还有什么优化方式吗?通过对比发现,isset在windows跟linux之间表现差异非常明显。另外,in_array在两个linux怎么差别也这么明显?具体是什么原因?不得而知。
为什么php跨平台的效率差别这么大?而js却很好?
js代码
但是同样的,使用js对比,发现性能很高?难道跟语言中的结构有关?
var data={};
for(var i=0;i<400000;i++){
data[i]=true;
}
var diff=[];
for(var i=0;i<400000;i++){
var t = parseInt(Math.random()*500000);
if(!data[t]){
diff.push(t);
}
}
console.log(diff.length);
耗时:
$ time node test.js
79926
real 0m0.223s
user 0m0.000s
sys 0m0.000s
等同的php代码:
<?php
$data = [];
for($i=0;$i<400000;$i++){
$data[]=$i;
}
$diff=[];
for($i=0;$i<400000;$i++){
$t = mt_rand(1,500000);
if(!isset($data[$t])){
$diff[] = $t;
}
}
echo count($diff);