ThinkPHP操作MySQL刪除大量數據的優化


我對有一個8萬條數據的表進行了一次去重操作,其中有將近6萬條的重復數據需要被刪除。考慮到可能會產生對數據庫的高IO操作,我選擇進行刪除算法的優化。

第一個函數

獲取要刪除的id數組

  • 從原來的sql數據文檔里面讀取出來這8萬條數據並保存到數組中。為了防止數據溢出,我選擇逐行讀取,數據的大小分4k儲存.
  • 讀取過之后進行了三次正則匹配
    • 第一次正則匹配,匹配出長度為十位的學號,保存到數組里面。
    • 第二次正則匹配,匹配出所有包含漢字的第一個符合項。
    • 第三次正則匹配,匹配出長度為十八位的身份證號。在匹配身份證號的時候要注意最后一位可能是x,所以正則表達式我寫的是前十七位為數字,后一位自行判斷是數字還是字母。
  • 所有的數據都被讀取出來之后,我進行了一個非空判斷,對當行的數據進行插入操作,然后,繼續讀取下一行,當所有的行都沒讀取完之后要進行文件的關閉操作。
  • 與此同時,我在函數的開始和函數的結束,加上了時間判斷符,最后打印出時間的消耗,大概每次執行函數的時間在66秒左右。

第二個函數

分批次刪除數據

  • 將重復的id保存下來。
  • 通過idcode字段將相同的身份證號按組排列起來,並且選出組中最小的那個id,相當於不重復的唯一的一條數據,然后用foreach循環。
  • 將字符串組合成逗號連接的數組。按每1000條為一個組進行刪除。這樣做的好處是防止在同時刪除上萬條數據的時候,數據庫崩潰或者是操作超時。
    public function getArray()
{

set_time_limit(120);
$DB = M('code');
$handle = @fopen("C:/Users/Administrator/Desktop/xcu/UserData/user.sql", "r");
$t1 = microtime(true);
if ($handle) {
while (!feof($handle)) {
$buffer = fgets($handle, 4096);
if (preg_match('/[\d]{10}\b/', $buffer, $match)) {
$array['sid'] = $match[0];
if (preg_match('/[\x7f-\xff]+/', $buffer, $match)) {
$array['name'] = iconv('gbk', 'utf-8', $match[0]);
if (preg_match('/\d{17}[\d|X|x]/', $buffer, $match)) {
$array['idcode'] = $match[0];
}
}
}
if (!empty($array)) {
$DB->data($array)->add();
}
}
fclose($handle);
}
$t2 = microtime(true);
echo '耗時' . round($t2 - $t1, 3) . '秒';
}

public function delData()
{

set_time_limit(120);
$DB = M('code');
$res = $DB->field('min(id) as id')->group('idcode')->select();
$t1 = microtime(true);
$arr = "";
$count = 0;
foreach ($res as $val) {
$count++;
//var_dump($val['id'].'<br>');
$arr.= ",".$val['id'];
if ($count % 1000 == 0){
echo substr($arr,1).'<br>';
$map["id"] = array('in', substr($arr,1));
$sqlres = $DB->where($map)->delete();
if ($sqlres){
echo "批次刪除成功!";
}
$arr = "";
}
}
$t2 = microtime(true);
echo '耗時' . round($t2 - $t1, 3) . '秒';
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com