为何多线程/多进程执行MySQL LOAD DATA INFILE反而更慢?
为什么多进程导入CSV反而比单文件慢?
核心原因
- 磁盘IO竞争:磁盘(哪怕是SSD)的并发写入能力有限,同时导入两个文件会让磁盘频繁切换读写位置,反而降低整体吞吐量,远不如单文件连续读写高效。
- MySQL内部优化被抵消:
LOAD DATA INFILE本身是MySQL针对批量导入做了极致优化的命令,单线程导入时会批量写入数据、减少事务日志刷盘次数;而并发导入时,两个独立事务会触发更频繁的日志刷新,直接抵消了并发的优势。 - 额外开销叠加:多进程创建、每个进程单独建立数据库连接,这些零碎的开销叠加后,也会拉长总耗时。
优化方案
方案1:优化单文件导入效率(推荐)
不用拆分文件,给LOAD DATA INFILE加上前置优化配置,能大幅提升单文件导入速度:
def write_large(path): mydb=mysql.connector.connect( host='localhost', user='python', password='rvlPBO67.', database='test' ) mycursor=mydb.cursor() # 临时关闭唯一键和外键检查,导入后恢复 mycursor.execute("SET UNIQUE_CHECKS=0;") mycursor.execute("SET FOREIGN_KEY_CHECKS=0;") # 临时调整日志刷盘策略(导入完成后改回1保证数据安全) mycursor.execute("SET GLOBAL innodb_flush_log_at_trx_commit=2;") sql=f"LOAD DATA INFILE '{path}' INTO TABLE cereal FIELDS TERMINATED BY ',' IGNORE 1 ROWS;" mycursor.execute(sql) # 恢复原有配置 mycursor.execute("SET UNIQUE_CHECKS=1;") mycursor.execute("SET FOREIGN_KEY_CHECKS=1;") mycursor.execute("SET GLOBAL innodb_flush_log_at_trx_commit=1;") mydb.commit()
另外,提前调大MySQL的innodb_log_file_size参数(需重启MySQL),比如设置为2G,能减少日志切换频率,进一步提升批量写入速度。
方案2:若坚持使用并发导入
- 必须使用高性能SSD,机械硬盘的并发写入效率极低,完全不适合并发导入场景。
- 调整MySQL的IO线程数:
SET GLOBAL innodb_write_io_threads=8;(根据CPU核心数调整),让MySQL能更好地处理并发写入请求。 - 避免拆分过多小文件,控制在2-4个即可,过多文件会加剧IO竞争。
方案3:用MySQL原生工具替代Python调用
直接使用mysqlimport命令行工具,它是LOAD DATA INFILE的原生封装,比Python代码调用更高效,示例命令:
mysqlimport --local --user=python --password=rvlPBO67. --fields-terminated-by=',' --ignore-lines=1 test /var/lib/mysql-files/cerealLong.csv
内容的提问来源于stack exchange,提问作者Christian
相关产品推荐
相关产品推荐

