大資料量處理實踐方案整理

ruanwenwu發表於2020-09-30

一、資料迴圈

用 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 協議》,轉載必須註明作者和本文連結

相關文章