大数据量处理实践方案整理
一、数据循环
用 id > $minId limit 1000 这种方式来循环数据。不要用limit 10000,1000这种方式,这种方式在数据量大的时候会非常慢。
用id > $minId limit 1000这种方式来循环时,不要再计算分页,而是要在循环中,或者循环结束后来改变minId的大小,最后将minId做下记录(用文件日志就行),以免程序需要断开或者意外断开时能自动衔接。
示例代码(已做删减,只保留核心代码):
while($minId < $processMaxId){
$sql = "select id,title from xx where forbid = 1 and id > '{$minId}' and id <= '{$processMaxId}' order by id asc limit {$pageSize}";
$data = $dbLink->getAll($sql);
if($data){
$insertSql = "insert into xx (askid,`type`,url,addtime,`from`,word,lasttime,asktime,replyid,patchNum) values ";
foreach ($data as $k => $v){
if($askId > $minId){
$minId = $askId;
}
**UNSET($REPLYLIST,$ASKINFO,$NOW,$ADDTIME,$ASKTIME,$LASTTIME,$FLAG,$ASKID,$TITLE,$CONTENT);**
}
$insertSql = rtrim($insertSql,",");
$dbLink->query($insertSql);
**UNSET($NOW,$PROCESSSTAGE,$DATA,$LOGSQL,$ASKID);**
}else{
$minId += $pageSize;
}
}
**unset($data,$now,$processStage,$logSql);**
二、每一层循环结束后,清掉所有没用的变量
三、设置更大的内存上限
对于比较消耗内存的,可以在脚本开头设置一个表达的内存上限,避免程序中途因为内存达到上限断掉
ini_set("memory_limit",'3000M');
四、批量插入
insert … values (),()这种
五、多进程
思路,用不同的进程号来区分进程,就像这样:
php a.php 1
php a.php 2
表示进程1和2。根据进程数来计算每个进程所控制的数据段。比如有100万数据,开两个进程,那么进程1负责0-50万,进程2负责50万-100万。
进程中的数据循环和一中将到的循环方式一样,只不过它有个最大id限制。
得到minId和每个进程的最大id:
$minId = file_get_contents($minFile);
$maxId = 1906847;//可以用程序计算max(id)
$processSize = ceil($maxId/5);
$processMaxId = $process * $processSize;
if(!$minId){
$minId = ($process -1 ) * $processSize;
}
在循环中:
while($minId < $processMaxId){
$sql = "select id,title from xx_ask where forbid = 1 and id > '{$minId}' and id <= '{$processMaxId}' order by id asc limit {$pageSize}";
##五、进程进度监控
用表来做记录。记录脚本文件、进程号、总进度、批次等信息:
六、守护进程
把需要守护的进程放到自动运行中,每隔一段时间进行监控,如果中断就自动唤起。多进程也适用。
七、多进程管理
进程开关控制。有时候代码写的不完善,需要关掉或者重开,有个脚本比较方便,不用一个个开、关。
$processNum = $argv[2]; //进程数
$switchButton = $argv[1]; //开关
//自动运行列表
$execLlist = array(
array(//客户端问答首页列表
'path' => DIR_PATH.'/Ask/',//文件路径
'file' => 'xx.php',//执行文件
'command' => 'mulfil'//口令
),
/*array(//客户端问答首页列表
'path' => DIR_PATH.'/Ask/',//文件路径
'file' => 'xx2.php',//执行文件
'command' => 'mul'//口令
),*/
);
foreach ($execLlist as $val) {
$path = $val['path'];
$file = $val['file'];
$command = $val['command'];
if (!$path || !$file) {
continue;
}
for($i = 0; $i < $processNum;$i++) {
if($i >= 30){
break;
}
$pid = `ps aux|grep "{$file} {$command} {$i} {$processNum}"|grep -v grep|awk '{print $2}'`;
if ($pid) {
if($switchButton) {
echo $path . $file . "此文件已在执行,请耐心等待\n";
continue;
}else{
$cmd = "kill {$pid}";
exec($cmd);
}
}else{
if($switchButton){
$cmd = "cd {$path};nohup php {$file} {$command} {$i} {$processNum} > /dev/null &";
exec($cmd);
}
}
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接