1. 程式人生 > 其它 >解決資料匯出關閉mysql問題

解決資料匯出關閉mysql問題

技術標籤:PHPmysqlmysqlphp

最近有個專案老是在週一自動關閉mysql,必須得手動啟動,查詢日誌後發現是記憶體溢位造成LINUX優先關閉了mysql服務
檢視具體方法,發現後臺有個訂單匯出execl造成的
使用的是**CRMEB**商城,**TP6**框架,這個訂單匯出需要關聯使用者表和購物車表,三表聯查後一次性匯出1萬條資料就會崩潰,當然也是伺服器配置一般,記憶體只分了1G給PHP,匯出速度也很慢,然後找了很久找到一個匯出CSV,用了下挺好用的,速度快,也不會早晨記憶體溢位,下面記錄下具體使用
可以使用ajax請求
轉載[原有壓縮解壓功能我沒有使用](https://www.cnblogs.com/panziwen/p/12505170.html)
public static function excel_out($where) { //不限制執行時間,以防超時 set_time_limit(0); //檔名 $xlsName = '訂單匯出' . date('YmdHis', time()); //表頭 $xlsCell = ['編號', '訂單號', '收貨人', '收貨人手機', '收貨人地址', '支付金額', '使用積分', '備註', '購買人', '購買人手機', '訂單狀態', '下單時間', '商品資訊']; //統計總行數 getOderWhere是處理條件的,就不放了
$sqlCount = self::getOrderWhere($where, self::alias('a') ->join('user r', 'r.uid=a.uid', 'LEFT'), 'a.', 'r') ->count(); //每次取多少條 $sqlLimit = 1000;//每次只從資料庫取1000條 // buffer計數器 $cnt = 0; $fileNameArr = array(); //分段執行,以免記憶體寫滿 for
($i = 0; $i < ceil($sqlCount / $sqlLimit); $i++) { $fp = fopen($xlsName . '_' . $i . '.csv', 'w'); //生成臨時檔案 $fileNameArr[] = $xlsName . '_' . $i . '.csv';//將臨時檔案儲存起來 //第一次執行時將表頭寫入 if ($i == 0) { fputcsv($fp, $xlsCell); } //查詢出資料 $xlsData = self::getOrderWhere($where, self::alias('a') ->join('user r', 'r.uid=a.uid', 'LEFT'), 'a.', 'r') ->field('a.id,a.order_id,a.real_name,a.user_phone,a.user_address,a.pay_price,a.use_integral,a.remark,r.nickname,r.phone,a.add_time,a.status,a.shipping_type,a.goods_id,a.total_num') ->limit($i * $sqlLimit, $sqlLimit) ->select()->toArray(); foreach ($xlsData as $v) { $cnt++; //執行下一次迴圈之前清空緩衝區 if ($sqlLimit == $cnt) { ob_flush(); $cnt = 0; } if ($v['status'] == 2 && $v['shipping_type'] == 2) { $v['status_name'] = '未核銷'; } else if ($v['status'] == 2) { $v['status_name'] = '未發貨'; } else if ($v['status'] == 3) { $v['status_name'] = '待收貨'; } else if ($v['status'] == 4) { $v['status_name'] = '待評價'; } else if ($v['status'] == 5) { $v['status_name'] = '已完成'; } else { $v['status_name'] = '已取消'; } //這裡查詢訂單的商品詳情資訊 $goods = Db::name('store_product')->where('id', $v['goods_id'])->field('id,store_name,unit_name,price')->find(); $goods_str = '名稱:' . $goods['store_name'] . "\r\n"; $goods_str .= '價格:' . $goods['price'] . "\r\n"; $goods_str .= '數量:' . $v['total_num'] . ' ' . $goods['unit_name']; $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']); $v['goods_str'] = $goods_str; $item = [ $v['id'], $v['order_id'], $v['real_name'], $v['user_phone'], $v['user_address'], $v['pay_price'], $v['use_integral'], $v['remark'], $v['nickname'], $v['phone'], $v['status_name'], $v['add_time'], $goods_str, ]; unset($v); //每行寫入到臨時檔案 fputcsv($fp, $item); } fclose($fp); //每生成一個檔案關閉 } //將所有臨時檔案合併成一個 foreach ($fileNameArr as $file) { //如果是檔案,提出檔案內容,寫入目標檔案 if (is_file($file)) { $fileName = $file; //開啟臨時檔案 $handle1 = fopen($fileName, 'r'); //讀取臨時檔案 if ($str = fread($handle1, filesize($fileName))) { //關閉臨時檔案 fclose($handle1); //開啟或建立要合併成的檔案,往末尾插入的方式新增內容並儲存 $handle2 = fopen($xlsName . '.csv', 'a+'); //寫入內容 if (fwrite($handle2, $str)) { //關閉合並的檔案,避免浪費資源 fclose($handle2); } } } unlink($file); //刪除csv臨時檔案 } //輸出壓縮檔案提供下載 header("Cache-Control: max-age=0"); header("Content-Description: File Transfer"); header('Content-disposition: attachment; filename=' . basename($xlsName.'.csv')); // 檔名 header("Content-Type: application/zip"); // zip格式的 header("Content-Transfer-Encoding: binary"); // header('Content-Length: ' . filesize($xlsName.'.csv')); // @readfile($xlsName.'.csv');//輸出檔案; unlink($xlsName . '.csv'); //刪除合併的臨時檔案 }