为什么我的 DELETE 语句比 INSERT 语句花费这么多时间?

问题描述 投票:0回答:1

对于 14k 条记录,删除数千行需要 2 分钟以上,而插入它们几乎是即时的(200 毫秒)。

INSERT
DELETE
语句的处理方式相同(循环生成它们,附加到传递给打开事务的函数的列表,执行和提交)。但看来我误解了手动打开交易的必要性。由于插入几乎是即时的,我不确定是否是这种情况。

我的理解是事务==提交(

DELETE
语句在单个事务中)。在处理过程中,我可以看到所有已删除的行,直到最终提交(之后它们实际上被删除)。 常见问题解答中的情况应该有所不同,因为没有发生提交,但速度慢表明正在发生其他事情。

看起来,虽然在显式提交(通过

conn.commit()
)之前不会提交更改,但
BEGIN
BEGIN TRANSACTION
没有任何效果。我认为因为 sqlite3 自动发送
BEGIN

import sqlite3
from datetime import datetime
insert_queries = []
delete_queries = []
rows = 30000
for i in range(rows):
    insert_queries.append(f'''INSERT INTO test_table ("column1") VALUES ("{i}");''')
for i in range(rows):
    delete_queries.append(f'''DELETE from test_table where column1 ="{i}";''')

conn = sqlite3.connect('/data/test.db', check_same_thread=False)
timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")
print('*'*50)
print(f'Starting inserts: {timestamp}')
# conn.execute('BEGIN TRANSACTION')
for query in insert_queries:
    conn.execute(query)
conn.commit()
timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")
print(f'Finished inserts: {timestamp}')

print('*'*50)
timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")
print(f'Starting deletes: {timestamp}')
# conn.isolation_level = None
# conn.execute('BEGIN;')
# conn.execute('BEGIN TRANSACTION;')
for query in delete_queries:
    conn.execute(query)
conn.commit()
timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S")
print(f'Finished deletes: {timestamp}')

行数呈指数级增加删除时间(10k 行为 2 秒,20k 行为 7 秒,50k 行为 43 秒),而无论行数如何,插入时间都是即时的。为什么

DELETE
语句比
INSERT
语句花费这么多时间以及如何加快删除过程?

python sql sqlite transactions
1个回答
1
投票

我尝试以 50 个为一组进行批量删除:

...
batches = []
batch = []
for i in range(rows):
    batch.append(str(i))
    if len(batch) == 50:
        batches.append(batch)
        batch = []
if batch:
    batches.append(batch)
...

base = 'DELETE FROM test_table WHERE column1 IN ({})'
for batch in batches:
    placeholders = ','.join(['?'] * len(batch))
    sql = base.format(placeholders)
    conn.execute(sql, batch)
conn.commit()
...

这将持续时间减少到 1 - 2 秒(从原来的 6 - 8 秒)。

将此方法与

executemany
相结合,持续时间为 1 秒。

使用查询来定义已删除的列几乎是即时的

DELETE FROM test_table WHERE column1 IN (SELECT column1 FROM test_table)

但 Sqlite 可能会识别出此查询与裸的

DELETE FROM test_table
相同并进行优化。

关闭 secure_delete PRAGMA 似乎会使性能变得更糟。

© www.soinside.com 2019 - 2024. All rights reserved.