You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中使用QSqlQuery操作SQLite出现性能问题该如何优化?

问题定位

性能瓶颈和QSql本身无关,核心是两个问题:1. SQLite默认自动提交事务的机制导致频繁刷磁盘;2. 你的代码存在逻辑bug,循环插入的记录量远多于实际数据量。


具体优化方案

1. 显式使用事务批量提交

SQLite默认每执行一条exec()语句就自动开启并提交一个独立事务,每次事务提交需要触发磁盘持久化同步,耗时是毫秒级,上千次提交就会达到分钟级耗时。
只需要在插入操作开始前开启事务,所有插入完成后统一提交即可:

query = QSqlQuery()
# 插入逻辑开始前开启事务
query.exec("BEGIN;")
try:
    # 原有所有插入逻辑放在这里
    ...
    # 全部插入完成后统一提交
    query.exec("COMMIT;")
except Exception as e:
    # 出错时回滚事务
    query.exec("ROLLBACK;")
    # 原有异常处理逻辑
    ErrorLogger.WriteError(traceback.format_exc())
    ...

2. 修复去重逻辑的严重bug

你当前把temp_phone_list和temp_email_list定义在了遍历联系人的循环外面,每次处理新联系人时都会把之前所有联系人的号码、邮箱追加到列表中,导致插入的号码、邮箱和关联表数据呈指数级增长,这也是168条联系人跑15分钟的核心原因之一。
把两个临时列表的初始化放到循环内部即可:

for contact in contacts:
    temp_phone_list = []
    temp_email_list = []
    # 后续处理逻辑不变

3. 替换手动查询主键为API直接获取

不需要每次插入后执行SELECT max(Id)查询主键,QSqlQuery自带lastInsertId()方法可以直接返回刚插入记录的主键,减少大量无效查询:

# 插入person表后直接拿id,不需要额外查询
query.exec("INSERT INTO person (forename, lastname, mergedAddress) VALUES (?, ?, ?)", [contact.FirstName, contact.LastName, contact.Address])
contact_id = query.lastInsertId().toInt()[0]

4. 使用预处理语句替代字符串拼接

你当前用f-string拼接SQL不仅有SQL注入风险,遇到带单引号的联系人姓名、地址等数据还会直接执行失败,同时执行效率也低于预处理语句。改用预处理绑定参数的写法:

# 可以提前prepare复用查询对象,进一步提升效率
query.prepare("INSERT INTO phonenumbers (phonenumber) VALUES (?)")
for number in phone_list:
    query.addBindValue(number)
    query.exec()
    phone_id = query.lastInsertId().toInt()[0]
    # 插入关联表同理

以上优化全部做完后,168条联系人的插入耗时会降到秒级甚至毫秒级。


内容的提问来源于stack exchange,提问作者accpert.com

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 08:06:04