2011-06-26 102 views
19

我正在使用Python中的MySQLdb模块来与数据库交互。我有一个情况,就是有一个非常大的列表(数以万计的元素),我需要将其作为行插入到表中。Python + MySQL - 批量插入

我现在的解决方案是生成一个大的INSERT语句作为字符串并执行它。

有没有更聪明的方法?

回答

16

有一个更聪明的方法。

大容量插入的问题是默认情况下autocommit is enabled因此导致每个insert语句在下一次插入启动之前被保存到稳定存储区。

由于手册页注释:

默认情况下,MySQL的运行启用了自动提交 模式。这意味着,当您执行 更新(修改)表时,尽快 ,MySQL 将更新存储在磁盘上以使其永久为 。要禁用自动提交模式, 使用下面的语句:

SET autocommit=0; 

由 自动提交变量设置为零,禁用 自动提交模式后,改变 事务安全表(如 那些InnoDB的,BDB或NDBCLUSTER) 不会立即生效。 您必须使用COMMIT将您的 更改存储到磁盘或ROLLBACK以忽略 的更改。

这是RDBMs系统的一个非常普遍的特性,它假定数据库完整性是最重要的。它确实使批量插入每个插入的次数为1s,而不是1ms。制作超大插入语句的替代方法试图实现这种单次提交有可能重载SQL解析器的风险。

+4

从1.2.0开始,MySQLdb根据DB-API标准(PEP-249)的要求默认禁用自动提交。来源:http://mysql-python.sourceforge.net/FAQ.html – mikewaters

+0

如果你觉得你的插入仍然比他们应该慢,确保也调整你的MySQL服务器设置。在我的情况下,我的'innodb_buffer_pool_size'对于我的交易规模来说太小了,通过提高它,我实现了批量插入+ 40%的加速。请参阅:https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html – jlh

1

只要你把它做成一个INSERT而不是成千上万的单个INSERT,那么这是最好的方法。注意不要超过mysqls的最大数据包大小,并在必要时进行调整。例如,这将服务器数据包的最大值设置为32Mb。你也需要在客户端上做同样的事情。

mysqld --max_allowed_packet=32M 
+0

这是针对症状而不是原因的事务机制的破解 – msw

+0

您可以扩展一下吗?或者说你会做什么呢? – justinhj

+0

@msw使用* transactions发出批量INSERT *的速度更快...... – Will

11

如果你不得不插入非常大量的数据,你为什么要试图将它们全部插入到一个单一的insert? (这将不必要地在你的内存中加载这个大的insert字符串,同时也执行它。如果你的数据插入非常大,这不是一个很好的解决方案。)

为什么不你在db中为每个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。将它设置为False,因为msw表示。)

+0

如果每个插入都有一个语句,是不是会很慢?我不介意使用记忆。它只会是兆字节,所以我不担心。 – Mike

+0

不,它不会慢,这是我想说的......只要你不在循环之间进行。尝试两种方法,看看你是否不相信我... –

+0

在MyISAM(我使用的引擎)没有提交执行后暗示完成? – Mike