真正批量插入需绕过executemany()的伪批量缺陷:mysql应手拼多值insert并手动事务控制;postgresql优先用execute_batch();sqlite须结合wal模式、事务包裹与多值insert;全程禁用非主键索引可显著提速。

默认用 executemany() 插入 10 万行,实际是 10 万次单条执行——这不是批量,是“假装批量”。真正提速得绕过它,改用多值 INSERT 或驱动层的真批量接口。
MySQL:手拼多值 INSERT 比 execumany() 快 5–10 倍
PyMySQL 和 mysql-connector-python 的 executemany() 默认行为是循环调用 execute(),每条都走一次网络往返+事务提交开销。尤其在 autocommit=True 下,等于每条都刷 redo log。
- 必须显式关闭自动提交:
conn.autocommit = False,最后手动conn.commit() - 把数据按 500 行/批切片,拼成一条
INSERT INTO t(a,b) VALUES (%s,%s),(%s,%s),...,再用cursor.execute(sql, flat_args) -
flat_args是扁平化列表,比如[(1,'a'), (2,'b')]要转成[1,'a',2,'b'];别用字符串格式化拼 SQL,必须用占位符防注入 - 如果表有唯一键冲突,直接加
ON DUPLICATE KEY UPDATE,比先查再插快得多
PostgreSQL:优先用 execute_batch(),别碰 copy_from() 除非数据绝对干净
psycopg2.extras.execute_batch() 是中小批量(≤1 万行)最稳的选择,支持 JSON、数组等复杂类型,且走标准 SQL 解析路径,约束和触发器都生效。
- 用法简单:
execute_batch(cur, "INSERT INTO t(a,b) VALUES (%s, %s)", data, page_size=1000) -
page_size别设太大,超过 5000 容易内存溢出(尤其字段含大文本) -
copy_from()确实更快,但它跳过所有约束检查(除 NOT NULL),也不走触发器,上线前必须确认数据已清洗、列顺序完全匹配、无默认值依赖 - 如果数据来自爬虫,含 HTML 片段或用户输入,
copy_from()风险高,不推荐
SQLite:PRAGMA 设置只是前提,关键在事务包裹和 WAL 模式
只设 PRAGMA synchronous = OFF 或 journal_mode = WAL 不够,SQLite 批量写入慢的主因是默认每条 INSERT 都算一个事务。
- 必须用
BEGIN IMMEDIATE或BEGIN DEFERRED包裹全部插入语句 - 搭配
PRAGMA journal_mode = WAL+PRAGMA synchronous = NORMAL,能减少磁盘阻塞 - 避免在循环里反复
execute("INSERT ..."),仍要按批拼多值 INSERT,否则 PRAGMA 白设 - 10 万行插入耗时从 15 秒压到 1.2 秒,靠的是“WAL + 事务 + 批量 SQL”三者缺一不可
最容易被忽略的一点:入库快慢不只取决于代码怎么写,更取决于你是否在插入前就关掉了无关索引。爬虫数据入库阶段,临时禁用非主键索引,导入完成再重建,往往比优化 SQL 本身还见效。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











