解決資料匯出關閉mysql問題
阿新 • • 發佈:2020-12-16
最近有個專案老是在週一自動關閉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'); //刪除合併的臨時檔案
}