在PHP中使用 XlsWriter(如 xlswriter 扩展)处理百万级数据的导入导出,需重点解决内存占用和性能问题。
以下是分步骤的实现方案:
一、环境准备
1 安装 xlswriter 扩展
从PECL安装:
1 | pecl install xlswriter |
在 php.ini 中启用扩展:
1 | extension=xlswriter.so |
2 调整PHP配置
处理大数据时需增加内存和执行时间限制:
1 2 | memory_limit = 1024M max_execution_time = 3600 |
二、百万级数据导出(Excel)
核心思路
流式写入:避免一次性加载所有数据到内存。
分页查询:从数据库分批读取数据。
直接输出到浏览器:减少临时文件占用。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | '/tmp' ]; // 临时目录(可选) $excel = new VtifulKernelExcel( $config ); $file = $excel ->fileName( 'export.xlsx' )->header([ 'ID' , 'Name' , 'Email' ]); // 2. 设置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. 连接数据库 $pdo = new PDO( 'mysql:host=localhost;dbname=test' , 'user' , 'password' ); // 4. 分页查询并写入数据 $pageSize = 10000; // 每页数据量 $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 ; } // 写入当前页数据 foreach ( $data as $row ) { $file ->data([ $row [ 'id' ], $row [ 'name' ], $row [ 'email' ]]); } $page ++; ob_flush(); // 刷新输出缓冲区 flush (); } while (true); // 5. 结束写入 $file ->output(); |
关键点
分页查询:通过 LIMIT 分批拉取数据,避免一次性加载百万数据。
流式输出:直接输出到浏览器,减少内存占用。
缓冲区刷新:使用 ob_flush() 和 flush() 实时推送数据到客户端。
三、百万级数据导入(Excel到数据库)
核心思路
分块读取Excel:避免一次性加载整个文件。
批量插入:使用事务和批量SQL减少数据库操作次数。
错误处理:记录错误数据,避免单条失败导致全部回滚。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | openFile( $uploadFile ); $sheet = $excel ->getSheet(); // 3. 连接数据库 $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 ; // 跳过标题行 } // 数据校验(示例) if ( empty ( $row [1]) || !filter_var( $row [2], FILTER_VALIDATE_EMAIL)) { error_log ( "Invalid data at row $currentRow: " . json_encode( $row )); continue ; } // 构建批量插入数据 $batchData [] = [ 'id' => $row [0], 'name' => $row [1], 'email' => $row [2] ]; // 批量插入 if ( count ( $batchData ) >= $batchSize ) { insertBatch( $pdo , $batchData ); $batchData = []; } } // 插入剩余数据 if (! empty ( $batchData )) { insertBatch( $pdo , $batchData ); } $pdo ->commit(); echo "导入成功!" ; } catch (Exception $e ) { $pdo ->rollBack(); echo "导入失败: " . $e ->getMessage(); } // 批量插入函数 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 ); } |
关键点
分块读取:逐行读取Excel,避免内存爆炸。
事务提交:批量插入后提交事务,减少数据库压力。
错误跳过:记录错误行,避免单条数据错误导致整体失败。
四、性能优化技巧
1 索引优化:
在导入前移除索引,导入完成后重新创建。
使用 ALTER TABLE … DISABLE KEYS 和 ALTER TABLE … ENABLE KEYS(MyISAM引擎)。
2 调整MySQL配置:
1 2 | innodb_buffer_pool_size = 2G innodb_flush_log_at_trx_commit = 0 |
3 压缩Excel文件:
1 | $file = $excel ->fileName( 'export.xlsx' )->setCompressionLevel(6); |
五、注意事项
内存监控:使用 memory_get_usage() 实时监控内存。
超时处理:通过 set_time_limit(0) 禁用脚本超时。
日志记录:记录导入导出的进度和错误。
到此这篇关于PHP如何使用XlsWriter实现百万级数据导入导出的文章就介绍到这了,更多相关PHP XlsWriter数据导入导出内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!