我在插入行时发现了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教程中显示的将数据添加到表中的方法。
对这里可能发生的事情有所了解吗?
答案 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开始。