PHP如何使用XlsWriter實(shí)現(xiàn)百萬(wàn)級(jí)數(shù)據(jù)導(dǎo)入導(dǎo)出
在PHP中使用 XlsWriter(如 xlswriter 擴(kuò)展)處理百萬(wàn)級(jí)數(shù)據(jù)的導(dǎo)入導(dǎo)出,需重點(diǎn)解決內(nèi)存占用和性能問(wèn)題。
以下是分步驟的實(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
二、百萬(wàn)級(jí)數(shù)據(jù)導(dǎo)出(Excel)
核心思路
流式寫入:避免一次性加載所有數(shù)據(jù)到內(nèi)存。
分頁(yè)查詢:從數(shù)據(jù)庫(kù)分批讀取數(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ù)庫(kù) $pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password'); // 4. 分頁(yè)查詢并寫入數(shù)據(jù) $pageSize = 10000; // 每頁(yè)數(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)前頁(yè)數(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)
分頁(yè)查詢:通過(guò) LIMIT 分批拉取數(shù)據(jù),避免一次性加載百萬(wàn)數(shù)據(jù)。
流式輸出:直接輸出到瀏覽器,減少內(nèi)存占用。
緩沖區(qū)刷新:使用 ob_flush() 和 flush() 實(shí)時(shí)推送數(shù)據(jù)到客戶端。
三、百萬(wàn)級(jí)數(shù)據(jù)導(dǎo)入(Excel到數(shù)據(jù)庫(kù))
核心思路
分塊讀取Excel:避免一次性加載整個(gè)文件。
批量插入:使用事務(wù)和批量SQL減少數(shù)據(jù)庫(kù)操作次數(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ù)庫(kù) $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; // 跳過(guò)標(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ù)庫(kù)壓力。
錯(cuò)誤跳過(guò):記錄錯(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í)處理:通過(guò) set_time_limit(0) 禁用腳本超時(shí)。
日志記錄:記錄導(dǎo)入導(dǎo)出的進(jìn)度和錯(cuò)誤。
到此這篇關(guān)于PHP如何使用XlsWriter實(shí)現(xiàn)百萬(wà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抽象方法和普通方法的區(qū)別點(diǎn)總結(jié)
在本篇文章里小編給大家分享的是關(guān)于php 抽象方法和普通方法的區(qū)別的相關(guān)文章,有需要的朋友們可以學(xué)習(xí)下。2019-10-10PHP簡(jiǎn)單實(shí)現(xiàn)正則匹配省市區(qū)的方法
這篇文章主要介紹了PHP簡(jiǎn)單實(shí)現(xiàn)正則匹配省市區(qū)的方法,涉及php正則匹配、判斷、運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2018-04-04讓的PHP代碼飛起來(lái)的40條小技巧(提升php效率)
這是在網(wǎng)上看到的一篇帖子,講的自己感覺比較實(shí)用,很注重細(xì)節(jié)【呵呵,當(dāng)然是指對(duì)像我一樣的業(yè)余PHPer而言了】,又擔(dān)心以后找不到原帖子,所以就轉(zhuǎn)了過(guò)來(lái)。2010-04-04PHP創(chuàng)建文件,并向文件中寫入數(shù)據(jù),覆蓋,追加的實(shí)現(xiàn)代碼
這篇文章主要介紹了PHP創(chuàng)建文件,并向文件中寫入數(shù)據(jù),覆蓋,追加的實(shí)現(xiàn)代碼,需要的朋友可以參考下2016-03-03深入理解curl類,可用于模擬get,post和curl下載
本篇文章是對(duì)curl類,可用于模擬get,post和curl下載進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Windows下IIS6/Apache2.2.4+MySQL5.2+PHP5.2.1安裝配置方法
Windows下IIS6/Apache2.2.4+MySQL5.2+PHP5.2.1安裝配置方法...2007-05-05