Python APSW(或SQLite3)在ExecuteMy上的插入速度非常慢
在插入行时,我发现APSW(Python的SQLite解析器)存在以下问题 假设我的数据是Python APSW(或SQLite3)在ExecuteMy上的插入速度非常慢,python,sqlite,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',
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教程中都显示了将数据添加到表中的方法
知道这里会发生什么吗?多亏了Confuseh,我得到了以下答案: 执行:
apsw.execute("BEGIN TRANSACTION;")
apsw.executemany("INERT INTO Table VALUES(?,?)", b)
apsw.execute("COMMIT;")
这一过程大大加快了!这似乎是添加数据的正确方法(与使用我创建多个插入语句的方法相比)。(披露:我是APSW的作者)。如果没有显式生效的事务,则SQLite会在每条语句的开头自动启动一个事务,并在每条语句的末尾结束。写事务是持久的——这意味着内容必须最终存储在存储器上,并调用fsync以确保它们能够在意外的电源或系统故障下生存。存储速度慢
在您的情况下,我建议将与
一起使用,而不要使用BEGIN/COMMIT,因为它会在出现错误时自动回滚。这样可以确保数据插入要么完全发生,要么根本不发生。有关示例,请参见
当您插入大量数据时,您会发现性能更高。谢谢您提出这个问题,当我将Sqlite与Python结合使用时,答案会帮助我。最后,我得到以下东西,希望它能帮助一些人: 当连接到sqlite数据库时,我们可以使用
con=sqlite3.connect(“:memory:”,隔离级别=None)
或con=sqlite3.connect(“:memory:”)
当use-isolation\u-level=None时,它将使用自动提交模式,这会产生太多事务,并且变得太慢。这将有助于:
cur.execute("BEGIN TRANSACTION")
cur.executemany(....)
cur.execute("COMMIT")
如果使用con=sqlite3.connect(“:memory:”)
,cur.executemany(..)
将立即快速运行。问题
对于mysqlclient-python
/pymysql
用户来说,如果他们希望sqlite3
/apsw
的executemany
将其惰性值重写为表值(?,)
为多行INSERT
语句,则可能会产生混淆
例如,mysqlclient-python
的docstring中包含以下内容:
此方法提高了多行插入和替换的性能。否则,它相当于使用execute()在参数上循环
Python stdlib的sqlite3.Cursor.executemany
没有这种优化。它总是循环等价的。下面是如何演示它(除非你想读一些C,):
它打印:
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
s重写为多行(手动或,例如,使用)以保持自动提交模式(isolation\u level=None
),或者在默认隐式提交模式下将INSERT
s包装在事务中(一个事务中包含合理数量的INSERT
s)。后者表示上述代码段的以下内容:
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中的大容量插入性能,我建议从开始。事务比执行sql更快。您可以在第一个方法中执行相同的操作,方法是在
executemany
之前添加aspw.execute(“开始事务”)
,在执行时添加aspw.execute(“提交”)
done@Confuseh事实上,许多事务处理速度较慢,但是一个事务和事务中的大量插入仍然比没有事务的插入更快。Confuseh CL感谢您的回复和有趣的链接。希望这个帖子可以帮助那些有类似问题的人future@Confuseh在没有交易的情况下不可能有插入;如果没有显式的BEGIN
/COMMIT
,则每个语句都会有一个。您好,罗杰,非常感谢您的详细解释!不是每天都有开发人员在你每天使用的工具后面写在你的StackOverflow帖子上!!!!!
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