2011-05-09 71 views
18

我正在「轉換」一個大的(約1.6GB)CSV文件,並將CSV的特定字段插入到SQLite數據庫中。基本上我的代碼如下所示:Python CSV到SQLite

import csv, sqlite3 

conn = sqlite3.connect("path/to/file.db") 
conn.text_factory = str #bugger 8-bit bytestrings 
cur = conn.cur() 
cur.execute('CREATE TABLE IF NOT EXISTS mytable (field2 VARCHAR, field4 VARCHAR)') 

reader = csv.reader(open(filecsv.txt, "rb")) 
for field1, field2, field3, field4, field5 in reader: 
    cur.execute('INSERT OR IGNORE INTO mytable (field2, field4) VALUES (?,?)', (field2, field4)) 

一切正常,我期望它有例外......它需要時間來處理數量驚人的。我編碼錯了嗎?是否有更好的方法來實現更高的性能並實現我所需要的(只需將CSV的幾個字段轉換爲SQLite表)?

**編輯 - 我試着直接將csv導入到sqlite中,正如所建議的,但事實證明我的文件在字段中有逗號(例如"My title, comma")。這是導入錯誤。它似乎有太多的事件的手動編輯文件...

任何其他的想法?**

+1

這是一個很大的文件。多久時間? – Blender 2011-05-09 20:58:51

+0

有多少重複記錄?如果數量很多,保留已經插入的記錄的本地「集合」可能會更快,並且跳過對重複項的SQL調用。 – kindall 2011-05-09 21:06:18

+0

[Here](http://dev.mysql.com/doc/refman/5.5/en/insert-speed。HTML)是一些MySQL批量加載速度提示。 – kindall 2011-05-09 21:52:01

回答

24

它可以直接導入CSV:

sqlite> .separator "," 
sqlite> .import filecsv.txt mytable 

http://www.sqlite.org/cvstrac/wiki?p=ImportingFiles

+1

「等等等等等等,」123「會導致問題......圍繞這個問題的想法? – user735304 2011-05-09 23:50:27

+0

默認情況下,似乎沒有內置的轉義方式。此外,引號將是字符串內的文字。使用CSV解析並使用不同分隔符輸出來更改文本可能是有意義的,但這可能會首先破壞使用導入工具的目的。 – fengb 2011-05-10 01:32:35

+0

嘗試:.mode csv而不是.separator,請參閱: http://stackoverflow.com/questions/14947916/import-csv-to-sqlite/24582022#24582022 – NumesSanguis 2014-12-03 14:40:56

3

嘗試使用交易。

begin  
insert 50,000 rows  
commit 

這將定期提交數據,而不是每行一次。

20

克里斯是正確的使用交易;將數據分成塊並存儲。

......除非已經存在於一個事務中,否則每個SQL語句都有一個新的事務啓動它,這是非常昂貴的,因爲它需要重新打開,寫入和關閉每個語句的日誌文件。通過包裝與BEGIN TRANSACTION SQL語句的順序是可以避免的;和END交易;語句不改變數據庫的語句也獲得此加速「 - 來源:http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html

...有。另一個可以用來加速SQLite事務的技巧:無論何時你需要做多個數據庫寫操作,把它們放到一個事務中,而不是每次寫入(和鎖定)文件寫查詢發出後,只有在事務完成時寫纔會發生。「 - 來源:How Scalable is SQLite?

import csv, sqlite3, time 

def chunks(data, rows=10000): 
    """ Divides the data into 10000 rows each """ 

    for i in xrange(0, len(data), rows): 
     yield data[i:i+rows] 


if __name__ == "__main__": 

    t = time.time() 

    conn = sqlite3.connect("path/to/file.db") 
    conn.text_factory = str #bugger 8-bit bytestrings 
    cur = conn.cur() 
    cur.execute('CREATE TABLE IF NOT EXISTS mytable (field2 VARCHAR, field4 VARCHAR)') 

    csvData = csv.reader(open(filecsv.txt, "rb")) 

    divData = chunks(csvData) # divide into 10000 rows each 

    for chunk in divData: 
     cur.execute('BEGIN TRANSACTION') 

     for field1, field2, field3, field4, field5 in chunk: 
      cur.execute('INSERT OR IGNORE INTO mytable (field2, field4) VALUES (?,?)', (field2, field4)) 

     cur.execute('COMMIT') 

    print "\n Time Taken: %.3f sec" % (time.time()-t) 
+0

此代碼的其他用戶遇到了嘗試使用的問題'len()'與他們的CSV閱讀器:http://stackoverflow.com/questions/18062694/sqlite-transaction-for-csv-importing/18063276#18063276 – rutter 2013-08-05 16:39:46

14

正如有人說(克里斯和薩姆),交易做提高了不少插入性能

請讓我推薦另一種選擇,使用一套Python的工具。以CSV,csvkit工作

安裝:

pip install csvkit 

解決你的問題

csvsql --db sqlite:///path/to/file.db --insert --table mytable filecsv.txt