pymysql查询含BLOB的大量数据时内存溢出,如何逐行获取BLOB?
解决pymysql查询大BLOB时的内存溢出问题
为什么execute()阶段就内存溢出?
pymysql默认使用的是客户端游标(Client-Side Cursor),当你调用cur.execute()时,MySQL服务器会把整个结果集一次性发送到客户端,并存入本地内存——这就导致哪怕你还没开始迭代或fetch,内存已经被占满了,尤其是BLOB这种大字段,问题会格外明显。
如何逐个获取BLOB?用服务器端游标!
要实现真正的逐行从服务器获取数据,你需要使用服务器端游标(Server-Side Cursor),也就是pymysql.cursors.SSCursor或SSDictCursor。这种游标会让结果集留在MySQL服务器上,每次迭代或调用fetchone()时才获取一行数据,从根本上避免一次性加载所有数据到内存。
修改后的代码示例:
import pymysql from pymysql.cursors import SSCursor # 导入服务器端游标 db = pymysql.connect(...) # 创建游标时指定使用SSCursor with db.cursor(SSCursor) as cur: cur.execute("select value from my_blobs") for row in cur: # 处理单个BLOB数据 blob_data = row[0] ...
如果需要字典格式的结果,可以用SSDictCursor替换SSCursor。
关于fetchone/迭代游标的用处
你之前的疑惑很合理,这里分两种情况说明:
- 客户端游标:fetchone/迭代确实是在本地内存的结果集里逐行取,好处是结果集不大时,不用一次性把所有数据加载到变量里,分批处理更灵活,但本质上数据已经在内存里了,解决不了大结果集的内存问题。
- 服务器端游标:这时候fetchone/迭代才是真正的从服务器逐行拉取数据,这才是你原本期望的“避免内存溢出”的用法。
要不要循环每次查一个BLOB?
完全没必要!循环单条查询会产生大量的数据库请求,严重影响性能。服务器端游标是更高效的方案,既避免内存溢出,又能保持合理的查询效率。
注意事项
- 使用服务器端游标时,要保持数据库连接处于活跃状态,直到你处理完所有结果。
- 如果你的查询涉及复杂的排序或分组,MySQL服务器可能还是会在端生成临时表,但对于单纯的大BLOB查询,这个方案依然有效。
内容的提问来源于stack exchange,提问作者P-Gn
相关产品推荐
相关产品推荐

