在Python SQLite的executemany查询中使用进度处理器

2 投票
1 回答
2711 浏览
提问于 2025-04-18 14:45

我有一个用Python写的应用程序,它在运行一个很长的SQLite查询,我想在PyQT的界面上显示进度。

这是我代码的简化版本:

def run_long_query(self,)

    self.con = lite.connect(self.dbfname)
    self.con.set_progress_handler(self.progress_handler, 1)
    cur = self.con.cursor()
    vals = list(self.hash_iter(dirname, pattern))
    query = "INSERT OR REPLACE INTO hashval2fname (hashvalue, fname) VALUES(?, ?)"
    cur.executemany(query, vals)
    self.con.commit()
    self.con.close()

def progress_handler(self):
    print self.counter
    self.counter += 1
    self.pbar.setValue((self.pbar.value() + self.prog_step / 2))
    time.sleep(0.1)
    return 0  #  returning non-zero aborts

一切运行得很好,但我得到的进度更新次数有点随意。举个例子,假设vals返回一个长度为10的列表。我把进度条的上限设置为10,这样我就期待查询会执行10次,而我的进度处理函数也会被调用10次,每次调用时更新进度条一步。

但实际上,我看到的进度处理函数的调用次数(在set_progress_handler调用中是1)远远超过每次查询执行时的1次。例如,当我的vals列表只有一个项目时,我看到进度处理函数的调用次数在13到23之间,这取决于我的具体查询是什么。我通常不会在意这些,但我不知道如何让进度条有意义地跟踪进度,因为我不知道应该期待多少次迭代。

1 个回答

3

根据文档set_progress_handler的第二个参数是指在连续调用回调函数之间,虚拟机执行的指令数量。

这些指令是由查询优化器生成的,具体的指令数量变化很大,不仅和数据库的结构有关,还和数据本身以及SQLite的版本有关。你无法预测总共会有多少指令,甚至每一行会有多少指令。
(你可以使用EXPLAIN来查看某个查询的指令,但这个输出对于预测指令执行的频率并没有太大帮助。)

你不能在界面上显示百分比,最好的办法就是用一个动画的等待圈来表示。

撰写回答