PHP如何使用XlsWriter實(shí)現(xiàn)百萬級(jí)數(shù)據(jù)導(dǎo)入導(dǎo)出
在PHP中使用 XlsWriter(如 xlswriter 擴(kuò)展)處理百萬級(jí)數(shù)據(jù)的導(dǎo)入導(dǎo)出,需重點(diǎn)解決內(nèi)存占用和性能問題。
以下是分步驟的實(shí)現(xiàn)方案:
一、環(huán)境準(zhǔn)備
1 安裝 xlswriter 擴(kuò)展
從PECL安裝:
pecl install xlswriter
在 php.ini 中啟用擴(kuò)展:
extension=xlswriter.so
2 調(diào)整PHP配置
處理大數(shù)據(jù)時(shí)需增加內(nèi)存和執(zhí)行時(shí)間限制:
memory_limit = 1024M max_execution_time = 3600
二、百萬級(jí)數(shù)據(jù)導(dǎo)出(Excel)
核心思路
流式寫入:避免一次性加載所有數(shù)據(jù)到內(nèi)存。
分頁查詢:從數(shù)據(jù)庫分批讀取數(shù)據(jù)。
直接輸出到瀏覽器:減少臨時(shí)文件占用。
代碼實(shí)現(xiàn)
<?php
// 1. 初始化Excel對(duì)象
$config = ['path' => '/tmp']; // 臨時(shí)目錄(可選)
$excel = new \Vtiful\Kernel\Excel($config);
$file = $excel->fileName('export.xlsx')->header(['ID', 'Name', 'Email']);
// 2. 設(shè)置HTTP頭直接下載
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="export.xlsx"');
header('Cache-Control: max-age=0');
$file->output();
// 3. 連接數(shù)據(jù)庫
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
// 4. 分頁查詢并寫入數(shù)據(jù)
$pageSize = 10000; // 每頁數(shù)據(jù)量
$page = 1;
do {
$offset = ($page - 1) * $pageSize;
$stmt = $pdo->prepare("SELECT id, name, email FROM users LIMIT :offset, :limit");
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->bindValue(':limit', $pageSize, PDO::PARAM_INT);
$stmt->execute();
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($data)) {
break;
}
// 寫入當(dāng)前頁數(shù)據(jù)
foreach ($data as $row) {
$file->data([$row['id'], $row['name'], $row['email']]);
}
$page++;
ob_flush(); // 刷新輸出緩沖區(qū)
flush();
} while (true);
// 5. 結(jié)束寫入
$file->output();
關(guān)鍵點(diǎn)
分頁查詢:通過 LIMIT 分批拉取數(shù)據(jù),避免一次性加載百萬數(shù)據(jù)。
流式輸出:直接輸出到瀏覽器,減少內(nèi)存占用。
緩沖區(qū)刷新:使用 ob_flush() 和 flush() 實(shí)時(shí)推送數(shù)據(jù)到客戶端。
三、百萬級(jí)數(shù)據(jù)導(dǎo)入(Excel到數(shù)據(jù)庫)
核心思路
分塊讀取Excel:避免一次性加載整個(gè)文件。
批量插入:使用事務(wù)和批量SQL減少數(shù)據(jù)庫操作次數(shù)。
錯(cuò)誤處理:記錄錯(cuò)誤數(shù)據(jù),避免單條失敗導(dǎo)致全部回滾。
代碼實(shí)現(xiàn)
<?php
// 1. 上傳文件處理
$uploadFile = $_FILES['file']['tmp_name'];
if (!is_uploaded_file($uploadFile)) {
die('非法文件');
}
// 2. 初始化Excel讀取器
$excel = new \Vtiful\Kernel\Excel();
$excel->openFile($uploadFile);
$sheet = $excel->getSheet();
// 3. 連接數(shù)據(jù)庫
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
$pdo->beginTransaction();
// 4. 分塊讀取并插入
$batchSize = 5000; // 每批插入量
$batchData = [];
$currentRow = 0;
try {
while ($row = $sheet->nextRow()) {
$currentRow++;
if ($currentRow === 1) {
continue; // 跳過標(biāo)題行
}
// 數(shù)據(jù)校驗(yàn)(示例)
if (empty($row[1]) || !filter_var($row[2], FILTER_VALIDATE_EMAIL)) {
error_log("Invalid data at row $currentRow: " . json_encode($row));
continue;
}
// 構(gòu)建批量插入數(shù)據(jù)
$batchData[] = [
'id' => $row[0],
'name' => $row[1],
'email' => $row[2]
];
// 批量插入
if (count($batchData) >= $batchSize) {
insertBatch($pdo, $batchData);
$batchData = [];
}
}
// 插入剩余數(shù)據(jù)
if (!empty($batchData)) {
insertBatch($pdo, $batchData);
}
$pdo->commit();
echo "導(dǎo)入成功!";
} catch (Exception $e) {
$pdo->rollBack();
echo "導(dǎo)入失敗: " . $e->getMessage();
}
// 批量插入函數(shù)
function insertBatch($pdo, $data) {
$sql = "INSERT INTO users (id, name, email) VALUES ";
$values = [];
$placeholders = [];
foreach ($data as $item) {
$values[] = $item['id'];
$values[] = $item['name'];
$values[] = $item['email'];
$placeholders[] = '(?, ?, ?)';
}
$sql .= implode(', ', $placeholders);
$stmt = $pdo->prepare($sql);
$stmt->execute($values);
}關(guān)鍵點(diǎn)
分塊讀?。褐鹦凶x取Excel,避免內(nèi)存爆炸。
事務(wù)提交:批量插入后提交事務(wù),減少數(shù)據(jù)庫壓力。
錯(cuò)誤跳過:記錄錯(cuò)誤行,避免單條數(shù)據(jù)錯(cuò)誤導(dǎo)致整體失敗。
四、性能優(yōu)化技巧
1 索引優(yōu)化:
在導(dǎo)入前移除索引,導(dǎo)入完成后重新創(chuàng)建。
使用 ALTER TABLE ... DISABLE KEYS 和 ALTER TABLE ... ENABLE KEYS(MyISAM引擎)。
2 調(diào)整MySQL配置:
innodb_buffer_pool_size = 2G innodb_flush_log_at_trx_commit = 0
3 壓縮Excel文件:
$file = $excel->fileName('export.xlsx')->setCompressionLevel(6);
五、注意事項(xiàng)
內(nèi)存監(jiān)控:使用 memory_get_usage() 實(shí)時(shí)監(jiān)控內(nèi)存。
超時(shí)處理:通過 set_time_limit(0) 禁用腳本超時(shí)。
日志記錄:記錄導(dǎo)入導(dǎo)出的進(jìn)度和錯(cuò)誤。
到此這篇關(guān)于PHP如何使用XlsWriter實(shí)現(xiàn)百萬級(jí)數(shù)據(jù)導(dǎo)入導(dǎo)出的文章就介紹到這了,更多相關(guān)PHP XlsWriter數(shù)據(jù)導(dǎo)入導(dǎo)出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PHP使用Curl實(shí)現(xiàn)模擬登錄及抓取數(shù)據(jù)功能示例
這篇文章主要介紹了PHP使用Curl實(shí)現(xiàn)模擬登錄及抓取數(shù)據(jù)功能,結(jié)合實(shí)例形式分析了php使用curl進(jìn)行登陸、驗(yàn)證、cookie操作與數(shù)據(jù)抓取等相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-04-04
Laravel實(shí)現(xiàn)autoload方法詳解
本文給大家講解的是在laravel中是怎么實(shí)現(xiàn)autoload的?分析之后才發(fā)現(xiàn),真的是很巧妙,下面就來給大家詳細(xì)說明下2017-05-05
php-fpm開啟狀態(tài)統(tǒng)計(jì)的方法詳解
這篇文章主要給大家介紹了php-fpm開啟狀態(tài)統(tǒng)計(jì)的方法,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-06-06
PHP實(shí)現(xiàn)過濾各種HTML標(biāo)簽
在做項(xiàng)目的過程中,我們經(jīng)常需要用到過濾一些html標(biāo)簽來實(shí)現(xiàn)提高數(shù)據(jù)的安全性,其實(shí)就是刪除那些對(duì)應(yīng)用程序有潛在危害的數(shù)據(jù)。它用于去除標(biāo)簽以及刪除或編碼不需要的字符。2015-05-05
php判斷str字符串是否是xml格式數(shù)據(jù)的方法示例
這篇文章主要介紹了php判斷str字符串是否是xml格式數(shù)據(jù)的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了php采用自定義函數(shù)針對(duì)xml格式數(shù)據(jù)進(jìn)行驗(yàn)證的相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
PHP封裝的數(shù)據(jù)庫模型Model類完整示例【基于PDO】
這篇文章主要介紹了PHP封裝的數(shù)據(jù)庫模型Model類,結(jié)合實(shí)例形式分析了php基于PDO針對(duì)mysql數(shù)據(jù)庫常見增刪改查、統(tǒng)計(jì)、判斷等相關(guān)操作封裝與使用技巧,需要的朋友可以參考下2019-03-03

