APSW(或SQLite3)对executemany

时间:2016-01-26 12:04:05

标签: python sqlite

我在插入行时发现了APSW(Python的SQLite解析器)的以下问题。

让我说我的数据是data = [[1,2],[3,4]]

APSW和SQLite3允许我做类似的事情:

apsw.executemany("INERT INTO Table VALUES(?,?)", b)

或者我可以编写一些执行以下操作的代码:

sql = "BEGIN TRANSACTION; 
INSERT INTO Table Values('1','2');
INERT INTO Table Values('3','4');
COMMINT;"

apsw.execute(sql)

data是长列表/数组/表时,第一种方法的性能与第二种方法相比极差(对于400行,它可以是20秒而不是1!)。我不明白为什么这就是所有SQLite Python教程中显示的将数据添加到表中的方法。

对这里可能发生的事情有所了解吗?

4 个答案:

答案 0 :(得分:4)

感谢Confuseh,我得到了以下答案:

执行:

apsw.execute("BEGIN TRANSACTION;")
apsw.executemany("INERT INTO Table VALUES(?,?)", b)
apsw.execute("COMMIT;")

快速加速这个过程!这似乎是添加数据的正确方法(使用我创建多个INSERT语句的方法)。

答案 1 :(得分:3)

(披露:我是APSW的作者)。如果您没有明确地使事务生效,那么SQLite会在每个语句的开头自动启动一个事务,并在每个语句的结尾处结束。写入事务是持久的 - 这意味着内容必须以存储和fsync结束,以确保它们能够在意外的电源或系统故障中存活。存储很慢!

我建议在你的情况下使用axes而不是BEGIN / COMMIT,因为它会在出错时自动回滚。这确保您的数据插入完全发生或根本不发生。有关示例,请参阅the documentation

当您插入大量数据时,您会发现WAL mode更具性能。

答案 2 :(得分:0)

感谢您提出这个问题,当我在Python中使用Sqlite时,答案对我有帮助。最后,我得到了以下的东西,并希望它可以帮助一些人:

当连接到sqlite数据库时,我们可以使用

con = sqlite3.connect(":memory:",isolation_level=None)con = sqlite3.connect(":memory:")

当使用isolation_level = None时,它将使用自动提交模式,该模式会产生太多的事务,并且变得太慢。这将有所帮助:

cur.execute("BEGIN TRANSACTION")
cur.executemany(....)
cur.execute("COMMIT")

如果使用con = sqlite3.connect(":memory:")cur.executemany(....)会立即加快。

答案 3 :(得分:0)

问题

对于mysqlclient-python / pymysql用户,他们期望executemany / sqlite3中的apsw将其INERT INTO table VALUES(?, ?)重写为多行INSERT语句。

例如,mysqlclient-python中的executemany的文档字符串中包含以下内容:

此方法提高了多行INSERT和REPLACE的性能。否则,这等效于使用execute()遍历args。

Python stdlib的sqlite3.Cursor.executemany没有这种优化。它始终是循环设备。这是演示方法(除非您想读C,_pysqlite_query_execute):

import sqlite3

conn = sqlite3.connect(':memory:', isolation_level=None)
conn.set_trace_callback(print)
conn.execute('CREATE TABLE tbl (x INTEGER, y INTEGER)')

conn.executemany('INSERT INTO tbl VALUES(?, ?)', [(i, i ** 2) for i in range(5)])

它打印:

CREATE TABLE tbl (x INTEGER, y INTEGER)
INSERT INTO tbl VALUES(0, 0)
INSERT INTO tbl VALUES(1, 1)
INSERT INTO tbl VALUES(2, 4)
INSERT INTO tbl VALUES(3, 9)
INSERT INTO tbl VALUES(4, 16)

解决方案

因此,您需要将这些INSERT重写为多行(手动或例如使用python-sql)以保持自动提交模式(isolation_level=None) ,或在默认的隐式提交模式下将INSERT包裹在一个事务中(明智的INSERT数个事务)。对于上面的代码片段,后者意味着以下含义:

import sqlite3

conn = sqlite3.connect(':memory:')
conn.set_trace_callback(print)
conn.execute('CREATE TABLE tbl (x INTEGER, y INTEGER)')

with conn:
    conn.executemany('INSERT INTO tbl VALUES(?, ?)', [(i, i ** 2) for i in range(5)])

现在打印:

CREATE TABLE tbl (x INTEGER, y INTEGER)
BEGIN 
INSERT INTO tbl VALUES(0, 0)
INSERT INTO tbl VALUES(1, 1)
INSERT INTO tbl VALUES(2, 4)
INSERT INTO tbl VALUES(3, 9)
INSERT INTO tbl VALUES(4, 16)
COMMIT

为了进一步提高SQLite的大容量插入性能,我建议从this overview question开始。