1. 程式人生 > >php實現mysql百萬級數據插入,耗時10s左右

php實現mysql百萬級數據插入,耗時10s左右

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左右