如何高效实现PHP更新40万行级大CSV库存文件的需求?
性能瓶颈分析
你当前代码的耗时核心来自嵌套遍历逻辑:每次遍历主库存的一行数据,都会通过array_search + array_column全量遍历stock-feed数组匹配sku,假设stock-feed有1万条数据,总计算量就是40万 * 1万 = 40亿次操作,效率自然极低。
PHP优化方案
核心优化点是将stock-feed转为以sku为键的关联索引数组,sku匹配从O(n)降到O(1),总时间复杂度降至O(stock-feed行数 + 主库存行数),40万行数据通常可以在3秒内处理完成。
优化后代码如下:
<?php // 第一步:处理stock-feed生成sku=>库存的映射索引 $feedHandle = fopen('stock-feed.csv', 'r'); $feedHeader = fgetcsv($feedHandle, 0, ','); $skuStockMap = []; while (($feedRow = fgetcsv($feedHandle, 0, ',')) !== false) { $row = array_combine($feedHeader, $feedRow); $skuStockMap[$row['sku']] = $row['stock']; // sku直接当数组键 } fclose($feedHandle); // 第二步:逐行处理主库存,写入新文件 $inventoryHandle = fopen('Inventory.csv', 'r'); $newInventoryHandle = fopen('updatedStockInventory.csv', 'w'); $rowIndex = 0; while ($inventoryRow = fgetcsv($inventoryHandle, 0, '|')) { $rowIndex++; // 保留表头直接写入 if ($rowIndex === 1) { fputcsv($newInventoryHandle, $inventoryRow, '|'); continue; } $currentSku = $inventoryRow[2]; // 你代码里sku在第3列(索引2) // 直接通过索引查库存,没有匹配就保留原库存 if (isset($skuStockMap[$currentSku])) { $inventoryRow[3] = $skuStockMap[$currentSku]; // 假设库存字段在第4列(索引3),根据实际调整 } fputcsv($newInventoryHandle, $inventoryRow, '|'); } fclose($inventoryHandle); fclose($newInventoryHandle); ?>
额外优化说明:
- 避免使用
file()函数一次性加载整个CSV到内存,改用fgetcsv逐行读取,内存占用可以稳定在10MB以内,不受文件大小影响 - 直接用
fputcsv生成新行,避免手动拼接字符串出错
其他高效处理方案
如果后续数据量继续增长,可以选择更适合的工具:
- 纯同步无复杂业务逻辑的场景,可以直接用
awk命令行工具处理,处理百万行CSV的速度比PHP快30%~50% - 有复杂关联逻辑的场景,可以将两个CSV导入MySQL临时表,通过
UPDATE JOIN语句批量更新后再导出,千万级数据处理效率远高于脚本逐行处理 - 高频更新场景建议抛弃CSV存储,改用Redis或者MySQL存储库存数据,直接按sku更新对应值,避免每次全量扫描文件,性能可以提升几个数量级
内容的提问来源于stack exchange,提问作者Denni
相关产品推荐
相关产品推荐

