大量数据存存在对比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);