2011-06-26 101 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