【发布时间】:2011-06-26 03:41:34
【问题描述】:
我正在使用 Python 中的 MySQLdb 模块与数据库进行交互。我的情况是有一个非常大的列表(数万个元素),我需要将其作为行插入到表中。
我现在的解决方案是生成一个大的INSERT 语句作为字符串并执行它。
有没有更聪明的方法?
【问题讨论】:
我正在使用 Python 中的 MySQLdb 模块与数据库进行交互。我的情况是有一个非常大的列表(数万个元素),我需要将其作为行插入到表中。
我现在的解决方案是生成一个大的INSERT 语句作为字符串并执行它。
有没有更聪明的方法?
【问题讨论】:
有一个更聪明的方法。
批量插入的问题在于,默认情况下 autocommit is enabled 会导致每个 insert 语句在下一次插入开始之前被保存到稳定存储中。
如手册页所述:
默认情况下,MySQL 使用自动提交运行 模式启用。这意味着尽快 当你执行一个语句时 更新(修改)表,MySQL 将更新存储在磁盘上以进行更新 永恒的。要禁用自动提交模式, 使用以下语句:
SET autocommit=0;
禁用后 通过设置自动提交模式 自动提交变量为零,更改 到事务安全表(例如 InnoDB、BDB 或 NDBCLUSTER 的那些) 不会立即永久化。 您必须使用 COMMIT 来存储您的 更改磁盘或 ROLLBACK 以忽略 变化。
这是 RDBM 系统的一个相当普遍的特征,它假定数据库完整性是最重要的。它确实使批量插入每次插入需要 1 秒而不是 1 毫秒。制作超大插入语句的替代方法试图实现这个单一的提交,但有可能使 SQL 解析器过载。
【讨论】:
innodb_buffer_pool_size 对于我的事务大小来说太小了,通过提高它,我实现了 +40% 的批量插入加速。见:dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html
如果您必须插入大量数据,为什么要将所有数据都插入一个 insert? (这将不必要地增加你的记忆力来制作这个大的insert 字符串以及在执行它时。如果你要插入的数据非常大,这也不是一个很好的解决方案。)
为什么不将每个insert 命令放入数据库中,然后使用for...loop 放入所有行并最终提交所有更改?
con = mysqldb.connect(
host="localhost",
user="user",
passwd="**",
db="db name"
)
cur = con.cursor()
for data in your_data_list:
cur.execute("data you want to insert: %s" %data)
con.commit()
con.close()
(相信我,这真的很快,但如果你得到较慢的结果,那么这意味着你的autocommit 必须是True。按照msw 所说,将它设置为False。)
【讨论】:
SET autocommit = 0; 来关闭提交(或者这样做在你的 python 程序中使用cur.execute('SET autocommit = 0'); con.commit())
for data in your_data_list: cur.execute("data you want to insert: %s" %data),打开了 SQL 注入攻击的闸门。最好使用以下内容:for data in your_data_list: cur.execute("data you want to insert: %s",item 1, item 2)(SQL 语句字符串后面的每个逗号将用该项目替换 SQL 字符串中的 ?)请参阅“插入数据”下的 mkleehammer.github.io/pyodbc 快乐编码!
只要您将其作为单个 INSERT 而不是数千个单独的插入,那么是的,这是最好的方法。注意不要超过 mysqls 的最大数据包大小,并在必要时进行调整。例如,这将服务器数据包最大设置为 32Mb。您也需要在客户端上执行相同的操作。
mysqld --max_allowed_packet=32M
【讨论】: