我有一个非常大的表,有 250,000 多行,其中许多行的其中一列中包含一个大文本块。目前为 2.7GB,预计将增长至少十倍。我需要对表的每一行执行特定于 python 的操作,但一次只需要访问一行。
现在我的代码看起来像这样:
c.execute('SELECT * FROM big_table')
table = c.fetchall()
for row in table:
do_stuff_with_row
当表较小时,这工作得很好,但表现在大于我的可用内存,当我尝试运行它时,Python 会挂起。是否有更好(更高效)的方法来逐行迭代整个表?
cursor.fetchall()
首先将所有结果提取到列表中。
相反,您可以迭代光标本身:
c.execute('SELECT * FROM big_table')
for row in c:
# do_stuff_with_row
这会根据需要生成行,而不是先加载所有行。
只是为了提供一个最小的可运行示例来测试 Martijn 提到的内容,创建一个包含 1000 万个点的数据库:
f="10m.sqlite"
rm -f "$f"
sqlite3 "$f" 'create table t(x integer)'
time sqlite3 "$f" 'insert into t select value as x from generate_series(1,10000000)'
使用此程序循环数据库:
主.py
#!/usr/bin/env python
import sqlite3
con = sqlite3.connect("10m.sqlite")
cur = con.cursor()
cur.execute('select * from t')
x = 0
for (i,) in cur.fetchAll():
x += i % 2
print(x)
通过 linux/unix 进程的峰值内存使用量获取最大内存使用量
command time -v ./main.py |& grep 'Maximum resident'
给出:
Maximum resident set size (kbytes): 873600
大约 900 MB,哇。天真地,我们预计每个 int 最多有 8 个字节,大约 80 MB。然后如果我们这样做:
for (i,) in cur:
它只有 11 MB:
Maximum resident set size (kbytes): 11256
在 Python 3.11.4、Ubuntu 23.04 上测试。