Python使用SQLite插入大量資料耗時問題
前言
使用Python爬蟲代理IP時,最先使用了sqlite作為儲存ip資料庫,sqlite簡單、靈活、輕量、開源,和檔案系統一樣。而當大量插入爬取的資料時,出現了嚴重的耗時,檢視一起資料後,發現:sqlite在每條insert都使用commit的時候,就相當於每次訪問時都要開啟一次檔案,從而引起了大量的I/O操作,耗時嚴重。
下面是每次插入後,提交事務處理,每次插入的時間,單位是秒。
def insert(self, sql, data):
'''
insert data to the table
:param sql:
:param data:
:return:
'''
if sql is not None and sql != '':
if data is not None:
cu = self.getcursor()
try:
for d in data:
cu.execute(sql, d)
# 每次都執行事務提交 self.conn.commit()
except sqlite3.Error as why:
print "insert data failed:", why.args[0]
cu.close()
else:
print "sql is empty or None"
0.134000062943 0.132999897003 0.236999988556 0.134000062943 0.120000123978 0.155999898911 0.131999969482 0.142000198364 0.119999885559 0.176000118256 0.124000072479 0.115999937057 0.111000061035 0.119999885559
顯式使用事務的形式提交
在批量插入資料之後再進行事務提交,把大量操作的語句都儲存在記憶體中,當提交時才全部寫入資料庫,此時,資料庫檔案也就只用開啟一次,會顯著的提高效率。
def insert(self, sql, data):
'''
insert data to the table
:param sql:
:param data:
:return:
'''
if sql is not None and sql != '':
if data is not None:
cu = self.getcursor()
try:
for d in data:
cu.execute(sql, d)
except sqlite3.Error as why:
print "insert data failed:", why.args[0]
# 批量插入之後再執行事務提交
self.conn.commit()
cu.close()
else:
print "sql is empty or None"
每次插入20行資料的時間如下,單位秒,很明顯的提高了效率
0.263999938965
0.117000102997
0.194999933243
0.263000011444
0.131000041962
0.15399980545
0.143000125885
0.12299990654
0.128000020981
0.121999979019
0.203999996185
寫同步和執行準備方法
寫同步
在SQLite中,資料庫配置的引數都由編譯指示(pragma)來實現的,而其中synchronous選項有三種可選狀態,分別是full、normal、off。官方文件
當synchronous設定為FULL (2), SQLite資料庫引擎在緊急時刻會暫停以確定資料已經寫入磁碟。這使系統崩潰或電源出問題時能確保資料庫在重起後不會損壞。FULL synchronous很安全但很慢。
當synchronous設定為NORMAL, SQLite資料庫引擎在大部分緊急時刻會暫停,但不像FULL模式下那麼頻繁。 NORMAL模式下有很小的機率(但不是不存在)發生電源故障導致資料庫損壞的情況。但實際上,在這種情況 下很可能你的硬碟已經不能使用,或者發生了其他的不可恢復的硬體錯誤。
設定為synchronous OFF (0)時,SQLite在傳遞資料給系統以後直接繼續而不暫停。若執行SQLite的應用程式崩潰, 資料不會損傷,但在系統崩潰或寫入資料時意外斷電的情況下資料庫可能會損壞。另一方面,在synchronous OFF時 一些操作可能會快50倍甚至更多。在SQLite 2中,預設值為NORMAL.而在3中修改為FULL。