You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解析CSV文件超时问题:如何优化4.5万行数据的去重逻辑?

优化方案

原代码的核心问题是每行发起一次数据库查询,45000行就会产生45000次数据库请求,往返开销直接导致超时。以下是针对性的优化方法:

1. 批量查询存在的ID,减少数据库交互次数

先把CSV中所有ID提取出来,再分批用IN语句一次性查询数据库中已存在的ID,最后对比过滤行。这样数据库请求次数从45000次降到几十次,性能提升显著。

修改后的代码示例

$file = fopen($filename, 'r');
$temp = fopen($tempFilename, 'w');
$batchSize = 1000; // 每批次处理的ID数量,避免IN语句过长
$currentBatch = [];
$existingIds = [];

// 第一步:读取CSV,收集ID并分批查询数据库
while(($row = fgetcsv($file)) !== FALSE){
    $id = $row[6];
    $currentBatch[] = $id;

    // 达到批次大小或文件读取结束时,执行批量查询
    if(count($currentBatch) === $batchSize){
        // 生成预处理占位符
        $placeholders = implode(',', array_fill(0, $batchSize, '?'));
        $sql = "SELECT id FROM table WHERE id IN ($placeholders)";
        $stmt = mysqli_prepare($conn, $sql);
        
        // 绑定参数(所有ID按字符串类型处理)
        mysqli_stmt_bind_param($stmt, str_repeat('s', $batchSize), ...$currentBatch);
        mysqli_stmt_execute($stmt);
        $result = mysqli_stmt_get_result($stmt);
        
        // 收集已存在的ID到数组,方便后续快速判断
        while($rowDb = mysqli_fetch_assoc($result)){
            $existingIds[$rowDb['id']] = true;
        }
        
        mysqli_stmt_close($stmt);
        $currentBatch = []; // 重置当前批次
    }
}

// 处理剩余的未达批次大小的ID
if(!empty($currentBatch)){
    $batchSizeLeft = count($currentBatch);
    $placeholders = implode(',', array_fill(0, $batchSizeLeft, '?'));
    $sql = "SELECT id FROM table WHERE id IN ($placeholders)";
    $stmt = mysqli_prepare($conn, $sql);
    mysqli_stmt_bind_param($stmt, str_repeat('s', $batchSizeLeft), ...$currentBatch);
    mysqli_stmt_execute($stmt);
    $result = mysqli_stmt_get_result($stmt);
    
    while($rowDb = mysqli_fetch_assoc($result)){
        $existingIds[$rowDb['id']] = true;
    }
    
    mysqli_stmt_close($stmt);
}

// 第二步:重新读取CSV,过滤并写入临时文件
rewind($file); // 将文件指针重置到开头
while(($row = fgetcsv($file)) !== FALSE){
    $id = $row[6];
    // 如果ID不在已存在列表中,写入临时文件
    if(!isset($existingIds[$id])){
        fputcsv($temp, $row);
    }
}

fclose($file);
fclose($temp);

// 覆盖原文件
rename($tempFilename, $filename);

2. 额外优化点

  • SQL注入防护:原代码直接将$id拼入SQL,存在注入风险,优化后的代码使用预处理语句彻底解决了这个问题。
  • 增大CSV读取缓冲区:调用fgetcsv时可以指定第二个参数(比如fgetcsv($file, 4096)),默认值较小,增大后能减少IO操作次数。
  • 数据库索引优化:确保数据库表的id字段有索引,执行CREATE INDEX idx_table_id ON table(id);,这会让IN查询的速度大幅提升。
  • 调整脚本超时时间:如果还是有超时风险,可以在脚本开头添加set_time_limit(0);(仅在安全环境下使用,避免无限循环)。

内容的提问来源于stack exchange,提问作者sverdon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 00:20:53