Python CSV 到 SQLite

Posted

技术标签:

【中文标题】Python CSV 到 SQLite【英文标题】:Python CSV to SQLite 【发布时间】:2011-08-21 23:50:58 【问题描述】:

我正在“转换”一个大型 (~1.6GB) CSV 文件并将 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 表)?

**EDIT -- 我尝试按照建议将 csv 直接导入 sqlite,但结果发现我的文件在字段中有逗号(例如"My title, comma")。这会导致导入错误。看来这些事件太多了,无法手动编辑文件...

还有其他想法吗??**

【问题讨论】:

这是一个大文件。需要多长时间? 有多少重复记录?如果有很多,保留已插入记录的本地set 可能会更快,并完全跳过对重复的 SQL 的调用。 Here 是一些 mysql 批量加载速度提示。 您使用的是什么操作系统和 Python 版本? “出现的次数似乎太多,无法手动编辑文件..”。让我们想想。手动更改太多?如果您有一种编程语言,可以让您编写程序将 CSV 文件重新格式化为制表符分隔的文件。任何想法可以使用哪种语言来编写这样的程序? 【参考方案1】:

Chris 是对的——使用交易;将数据分成块然后存储。

"...除非已经在事务中,否则每个 SQL 语句都会为其启动一个新事务。这非常昂贵,因为它需要为每个语句重新打开、写入和关闭日志文件。这可以通过使用 BEGIN TRANSACTION; 和 END TRANSACTION; 语句包装 SQL 语句序列来避免。这种加速也适用于不改变数据库的语句。" - 来源: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) 

【讨论】:

另一位关注此代码的用户在尝试将 len() 与他们的 CSV 阅读器一起使用时遇到问题:***.com/questions/18062694/…【参考方案2】:

可以直接导入CSV:

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

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

【讨论】:

默认情况下似乎没有内置的转义方式。此外,引号将是字符串中的文字。使用 CSV 解析更改文本并使用不同的分隔符输出可能是有意义的,但这可能会破坏首先使用导入工具的目的。 尝试:.mode csv 代替 .separator,见:***.com/questions/14947916/import-csv-to-sqlite/…【参考方案3】:

正如人们所说(Chris 和 Sam),事务确实提高了很多插入性能。

请让我推荐另一个选项,使用一套 Python 实用程序来处理 CSV,csvkit。

安装:

pip install csvkit

解决你的问题

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

【讨论】:

【参考方案4】:

尝试使用事务。

begin    
insert 50,000 rows    
commit

这将定期提交数据,而不是每行一次。

【讨论】:

【参考方案5】:

Pandas 可以轻松地将大文件分块加载到数据库中。将 CSV 文件读入 Pandas DataFrame,然后使用 Pandas SQL 编写器(这样 Pandas 就可以完成所有艰苦的工作)。以下是如何加载 100,000 行块中的数据。

import pandas as pd

orders = pd.read_csv('path/to/your/file.csv')
orders.to_sql('orders', conn, if_exists='append', index = False, chunksize=100000)

现代 Pandas 版本的性能非常好。不要重新发明***。请参阅here 了解更多信息。

【讨论】:

以上是关于Python CSV 到 SQLite的主要内容,如果未能解决你的问题,请参考以下文章

SQL 注入问题 SQLite Python

sqlite python 插入

如何用python把多个csv文件数据处理后汇总到新csv文件

python对多个csv文件里提取指定列汇总到一个新生成的csv文件

Python 字典到 CSV

Python 字典到 CSV