如何用PHP每日自动导入服务器上50万+行的大型CSV至数据库?
用PHP结合MySQL LOAD DATA INFILE高效导入大CSV文件
嘿,这个场景我太熟了——50万+行的CSV逐行循环插入确实会慢到离谱,甚至直接超时,LOAD DATA INFILE绝对是解决这个问题的最优方案,效率能提升N个量级。我给你拆解下具体实现步骤,都是实战里踩过坑后总结的:
第一步:确认服务器端CSV的路径与权限
LOAD DATA INFILE是让MySQL直接读取服务器本地的文件,所以首先得搞清楚两个关键点:
- 找到CSV文件的绝对路径:比如你通过FileZilla看到的文件在
/csv_backups/目录下,那绝对路径就是/var/www/csv_backups/daily_data_20240520.csv(具体路径根据你的服务器配置来)。 - 确保MySQL有权限读取这个文件:
- 把CSV文件的权限设为
644,所在目录权限设为755; - 如果还是报错,检查MySQL的
secure_file_priv变量(执行SHOW VARIABLES LIKE 'secure_file_priv';查看),把CSV移到这个变量指定的目录里,或者修改MySQL配置文件(比如my.cnf)调整这个参数(需要重启MySQL)。
- 把CSV文件的权限设为
第二步:用PHP自动获取最新的CSV文件
既然是每日生成一个,文件名大概率带日期后缀(比如daily_data_YYYYMMDD.csv),用PHP可以轻松遍历目录并筛选出最新的文件:
// 替换成你的CSV文件所在的服务器绝对目录 $csvDirectory = '/var/www/csv_backups/'; // 匹配所有符合命名规则的CSV文件 $csvFiles = glob($csvDirectory . 'daily_data_*.csv'); if (empty($csvFiles)) { die("未找到任何CSV文件,请检查路径是否正确"); } // 按文件修改时间倒序排序,第一个就是最新的文件 usort($csvFiles, function($fileA, $fileB) { return filemtime($fileB) - filemtime($fileA); }); $latestCsvPath = $csvFiles[0];
第三步:通过PHP执行LOAD DATA INFILE语句
用PDO来执行SQL会更安全,也能方便捕获错误。这里要注意匹配你的数据库表结构和CSV格式:
// 替换成你的数据库连接信息 $dsn = 'mysql:host=localhost;dbname=your_database;charset=utf8mb4'; $dbUser = 'your_username'; $dbPass = 'your_password'; try { $pdo = new PDO($dsn, $dbUser, $dbPass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $targetTable = 'your_target_table'; // 替换成要导入的数据库表名 // 构造LOAD DATA语句,根据你的CSV格式调整参数 $importSql = <<<SQL LOAD DATA INFILE '$latestCsvPath' INTO TABLE $targetTable CHARACTER SET utf8mb4 -- 如果CSV是GBK就改成gbk,匹配文件编码 FIELDS TERMINATED BY ',' -- CSV字段分隔符,一般是逗号 ENCLOSED BY '"' -- 字段包裹符,一般是双引号 LINES TERMINATED BY '\n' -- 行分隔符,Windows可能是'\r\n' IGNORE 1 LINES; -- 如果CSV第一行是表头,就忽略这一行;没有表头就删掉这句 SQL; // 执行导入 $pdo->exec($importSql); echo "导入成功!共导入 " . $pdo->rowCount() . " 条数据"; } catch (PDOException $e) { die("导入失败:" . $e->getMessage()); }
第四步:避坑指南
- 字段顺序不匹配:如果CSV的列顺序和数据库表不一致,一定要在SQL里指定列名,比如
INTO TABLE $targetTable (column1, column2, column3),把列名按CSV的顺序列出来。 - 特殊字符转义:如果你的CSV里有特殊字符,确保编码和数据库一致,否则可能出现乱码。
- 自动定时执行:要实现每日自动导入,用Linux的Cron任务就行。比如每天凌晨1点执行脚本:
这样还能把日志输出到文件,方便排查问题。0 1 * * * php /var/www/scripts/import_csv.php >> /var/www/logs/csv_import.log 2>&1
内容的提问来源于stack exchange,提问作者tobel
相关产品推荐
相关产品推荐

