Sqlite executemany and DELETE



执行许多似乎删除很慢(插入很好),我想知道是否有人知道为什么需要这么长时间。

请考虑以下代码:

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...)

以下时间结果(时间它给出了有趣的数据,所以:/)来自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 结果(但我认为时间它在第二次测试中被破坏了(或 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删除如此缓慢呢?

SQLites 将表记录存储在 B+ 树中,按rowid排序。

使用自动生成的rowid插入时,所有记录都追加在表的末尾。但是,删除时,SQLite 必须先搜索记录。如果未对id列编制索引,则速度很慢;要么创建一个显式索引(如 John 所建议的),要么将列声明为 INTEGER PRIMARY KEY 以使其成为 rowid。

如果不使用索引,

即仅在批量插入后创建索引,则使用索引插入会变得更快。

最后一个删除命令将一次删除所有记录。如果您知道要删除表中的所有记录,则可以仅使用 DELETE FROM testing 来进一步加快速度,这根本不需要查看任何记录。

我只是在打个赌注:因为它必须详尽地搜索要删除的那些。尝试使用索引并报告。

CREATE INDEX foo ON testing (val)

http://sqlite.org/lang_createindex.html

最新更新