考虑以下代码
import sqlite3
db = sqlite3.connect("mydb")
c = db.cursor()
c.execute("DROP TABLE IF EXISTS testing ")
c.execute("CREATE TABLE testing (val INTEGER);")
my_vals2 = [[x] for x in range(1,10000)]
def insertmany(vals):
c.executemany("INSERT INTO testing (val) VALUES (?)",vals)
db.commit()
def deletemany1(vals):
c.executemany("DELETE FROM testing WHERE val=?",vals)
db.commit()
def deletemany2(vals): #this is fastest even though im looping over to convert to strings and again to join ...
vals = ["'%s'"%v[0] for v in vals]
c.execute("DELETE FROM testing WHERE val IN (%s)"%",".join(vals))
#DELETE FROM TABLE WHERE x in (1,2,3...)
以下时间结果(timeit从ipython
提供了有趣的数据:/)%time insertmany(my_vals2)
#CPU times: user 0.60 s, sys: 0.00 s, total: 0.60 s Wall time: 0.60 s
%time deletemany1(my_vals2)
#CPU times: user 3.58 s, sys: 0.00 s, total: 3.58 s Wall time: 3.58 s
%time deletemany2(my_vals2)
#CPU times: user 0.02 s, sys: 0.00 s, total: 0.02 s Wall time: 0.02 s
为了完整起见,这里是timeit结果(但我认为timeit在第二次测试中被破坏(或者ms是与第一次测试不同的单位))
%timeit insertmany(my_vals2)
#1 loops, best of 3: 358 ms per loop
%timeit deletemany1(my_vals2)
#1 loops, best of 3: 8.34 ms per loop <- this is not faster than the above!!!! (timeit lies?)
%timeit deletemany2(my_vals2)
#100 loops, best of 3: 2.3 ms per loop
那么为什么executemany soooooo会因删除而变慢?
答案 0 :(得分:2)
我只是采取行动:因为它必须彻底搜索要删除的内容。 尝试使用索引并报告回来。
CREATE INDEX foo ON testing (val)
答案 1 :(得分:2)
SQLites将表记录存储在B +树中,按rowid
排序。
使用自动生成的rowid
进行插入时,所有记录都会附加在表格的末尾。
但是,删除时,SQLite必须首先搜索记录。如果未将id
列编入索引,则此操作会很慢;或者创建一个显式索引(由John提出),或者将列声明为INTEGER PRIMARY KEY
以使其成为rowid。
如果不使用索引,即使在批量插入后仅创建索引,则使用索引插入会更快。
您的上一个删除命令一次删除所有记录。如果您知道要删除表格中的所有记录,只需使用DELETE FROM testing
即可进一步加快速度,而不需要查看任何记录。