cursor.executemany
比cursor.execute
快。
根据在https://dev59.com/WWMl5IYBdhLWcg3wqIhh#76659706上的基准测试,cursor.executemany
应该比for
循环要快得多(观察到的速度提高了3倍),如:https://dev59.com/gG025IYBdhLWcg3wjGpO#7137270。 executemany
在单个事务中运行,但默认情况下循环也是在没有任何显式的BEGIN
/COMMIT
的情况下进行的:加速是由于其他因素引起的。
main.py
from pathlib import Path
import csv
import sqlite3
f = 'tmp.sqlite'
Path(f).unlink(missing_ok=True)
connection = sqlite3.connect(f)
cursor = connection.cursor()
cursor.execute("CREATE TABLE t (x integer)")
cursor.executemany('INSERT INTO t VALUES (?)', csv.reader(open('10m.csv', 'r')))
connection.commit()
connection.close()
测试通过:
python -c 'for i in range(10000000): print(i)' > 10m.csv
time ./main.py
这个操作在9秒内完成,与没有使用csv
读取的虚拟range()
循环相比,只有轻微的减速。参考链接:https://dev59.com/WWMl5IYBdhLWcg3wqIhh#76659706
要从CSV中选择或预处理列,我们现在可以使用一个生成器表达式,例如:
python -c 'for i in range(10): print(f"{i},{i*2},{i*4}")' > 10x3.csv
cursor.execute("CREATE TABLE t (x integer, z integer)")
cursor.executemany('INSERT INTO t VALUES (?, ?)',
((d[0], d[2]) for d in csv.reader(open('10x3.csv', 'r'))))
csvkit
的速度很慢
我希望csvkit(之前在https://dev59.com/gG025IYBdhLWcg3wjGpO#9913925提到过)能更好地支持这种用例,但目前它比上面的最简单手动executemany
脚本要慢得多。
echo x > 10m-head.csv
python -c 'for i in range(10000000): print(i)' >> 10m-head.csv
time csvsql --db sqlite:///tmp.sqlite --insert --table t 10m-head.csv
给出1分25秒。
使用sqlite .import
的理论速度限制
只是为了看看由于Python而偏离多少,假设没有任何东西能超过更原生的.import
命令:
sqlite3 tmp.sqlite 'create table t(x integer)'
time sqlite3 tmp.sqlite ".import --csv 10m.csv t"
我的SSD上的结果是5.8秒。比Python快得多,但很高兴看到我们也没有差太远。
在Ubuntu 23.04、Python 3.11.2、Lenovo ThinkPad P51上进行了测试,SSD为Samsung MZVLB512HAJQ-000L7 512GB SSD,名义速度为3 GB/s,使用csvkit==1.0.7和sqlite 3.40.1。