使用外键启用从SQLite中删除表似乎非常慢。有没有什么可以改善性能(不禁用外键)?
import time
import sqlite3
def fk_check(state):
conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute("CREATE TABLE parent (id integer primary key, name)")
c.execute("CREATE TABLE child (id integer primary key, parent_id references parent)")
c.execute("CREATE INDEX parentindex ON child(parent_id);")
c.execute(f"pragma foreign_keys={state};")
for i in range(10000):
c.execute("insert into parent (name) values (?);", ('name'+str(i),))
for i in range(5000, 10000):
c.execute("insert into child (parent_id) values (?);", (i,))
start = time.time()
c.execute("delete from parent where id < 5000")
took = time.time()-start
print(f'fk-{state}: {took}')
fk_check('on')
fk_check('off')
fk_check('on')
fk_check('off')
有以下输出:
fk-on: 0.8750052452087402
fk-off: 0.0007216930389404297
fk-on: 0.8769822120666504
fk-off: 0.0007178783416748047
来自the docs:
每次应用程序从父表中删除一行时,它都会执行以下SELECT语句的等效操作来搜索子表中的引用行:
SELECT rowid FROM <child-table> WHERE <child-key> = :parent_key_value
如果此SELECT返回任何行,则SQLite断定从父表中删除行将违反外键约束并返回错误。如果修改了父键的内容或者将新行插入到父表中,则可以运行类似的查询。
启用FK后,它会在每次删除时执行额外的工作。我不认为你可以在保留外键约束的同时避免这种情况。