php實現mysql百萬級數據插入,耗時10s左右
阿新 • • 發佈:2017-10-26
auth 每次 esc 處理 ram foreach循環 數量 turn ()
如題,最近做的一個項目,需求就是這樣,寫個功能模塊,實現批量導入,為客服省點時間(好吧,需求就是需求)。好在插入的數據,都是些連續的數字,所以可以利用
foreach循環出這些數據,然後拼接成mysql的insert語句,進行大字段的批量插入。原理就是這麽個原理,當然過程中有坑,什麽打開擴展限制,暫且只看邏輯方面的吧。
框架的話,不是laravel,用的ci,實例代碼如下:
/** * @desc 批量導入百萬條數據入庫(暫時只有韻達,方法已經寫通用,數據最少5000條,最大100W條) * @date 2017-10-26 20:45:45 * @param [int $start_no 起始號;int $end_no 截止號;string $express_type 類型] * @author [email protected] * @return [type] */ public function import_million_express_no () { //基本數據設置 header(‘Content-Type:text/html;charset=utf-8‘); ini_set(‘memory_limit‘, ‘128M‘); //設置類型對應數據庫中的表名 $express_to_form = [ ‘test1‘ => ‘from1‘, //平臺1對應的表名 ‘test2‘ => ‘from2‘, //平臺2對應的表名 ]; //獲取參數 $start_no = trim($this->input->post(‘start_no‘)); $end_no = trim($this->input->post(‘end_no‘)); $express_type = trim($this->input->post(‘express_type‘)); //判斷參數是否存在 if(!$start_no || !$end_no){ echo ‘<script>alert("錄入失敗,起始號和截止號不能為空為0");history.back();</script>‘; return; } //起始單號不能大於等於截止單號,錄入數量至少為5000個 if ($start_no >= $end_no) { echo ‘<script>alert("起始號不能,大於等於截止號!");history.back();</script>‘; return; } else { if ($end_no - $start_no < 5000) { echo ‘<script>alert("每次錄入號不能小於5000個!");history.back();</script>‘; return; } if ($end_no - $start_no > 1000000) { echo ‘<script>alert("每次錄入號不能大於1000000個!");history.back();</script>‘; return; } } //判斷數據類型是否存在 $table_name = $express_to_form[$express_type]; if(!$table_name){ echo ‘<script>alert("快遞類型有誤,無法進行打印!");history.back();</script>‘; return; }else{ //判斷初始單號,截止單號是否已經錄入 $sql1 = "select id from {$table_name} where express_no = {$start_no}"; $res1 = $this->db->query($sql1)->row(); if($res1){ echo ‘<script>alert("起始號已存在!");history.back();</script>‘; return; } $sql2 = "select id from {$table_name} where express_no = {$end_no}"; $res2 = $this->db->query($sql2)->row(); if($res2){ echo ‘<script>alert("截止號已存在!");history.back();</script>‘; return; } } /***上面的一系列判斷的廢話可以不用看,直接看下面怎麽對數據進行邏輯處理***/ //將起始號和截止號進行區間劃分 $length = $end_no - $start_no + 1; $times = floor($length / 5000); $temp_data = []; for($i=0;$i<$times;$i++){ $temp_data[$i][‘start_no‘] = $start_no; //起始編號 $temp_data[$i][‘end_no‘] = $start_no + 4999; //結束編號 $start_no += 5000; //下一輪循環的起始編號 } //檢驗數組最後一組數據,判斷是否需要再添加 if($end_no > $temp_data[$times-1][‘end_no‘]){ $temp_data[$times][‘start_no‘] = $temp_data[$times-1][‘end_no‘] + 1; $temp_data[$times][‘end_no‘] = $end_no; } //進行導入數據庫sql語句的拼接 $add_time = time(); $add_user = $this->session->userdata[‘user_name‘]; $tmp_val = "(‘{$add_time}‘,‘$add_user‘,0,‘%s‘,0),"; for($j=0;$j<count($temp_data);$j++){ //循環拼接sql插入語句 $sql = "insert into {$table_name} (field1,field2,field3,field4,field5) values "; for ($i=$temp_data[$j][‘start_no‘]; $i<=$temp_data[$j][‘end_no‘]; $i++) { $sql .= sprintf($tmp_val, $i); } $sql = trim($sql, ‘,‘) . ‘;‘; $bool = $this->db->query($sql); //執行插入有誤,寫進日誌異常表from3中 if(!$bool){ // 記錄日誌 $log_info = array(); $log_info[‘field1‘] = time(); $log_info[‘field2‘] = ‘類型:‘.$express_type.‘執行有誤,單號‘.$temp_data[$j][‘start_no‘].‘-‘.$temp_data[$j][‘end_no‘].‘執行失敗‘; $log_info[‘field3‘] = $this->session->userdata[‘user_name‘]; $this->db->insert(‘from3‘, $log_info); //錯誤日誌標誌 $err_log_info = TRUE; } } //數據返回 if($err_log_info){ echo ‘<script>alert("部分號執行失敗,請聯系管理員解決!");history.back();</script>‘; }else{ echo ‘<script>alert("數據執行成功!!!");history.back();</script>‘; } return; }
上面就是封裝的一個完整的類,參數驗證什麽的,可以不用看了,直接看sql語句拼接,其實最後發現吧,做出來也沒啥。經過測試,基本耗時在10s左右徘徊,恩恩,暫時先這樣,有好的思路,歡迎交流。不說了,得繼續加班去了,233
php實現mysql百萬級數據插入,耗時10s左右