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

如何分块获取MySQL单条数据 规避大longblob查询引发OOM错误

解决方案

以下方案均无需修改现有表结构,兼容你方兼容性优先的要求:

方案1:分块读取BLOB(兼容性最高,无需调整驱动/版本)

利用MySQL 5.7原生支持的SUBSTRING()函数按固定块大小拆分读取大BLOB字段,每次仅加载小块数据到内存,可直接写入外部存储,避免全量数据占用内存。
示例代码如下:

import MySQLdb

# 可根据实际容器剩余内存调整块大小,示例为10MB
BLOCK_SIZE = 10 * 1024 * 1024
target_id = 123
# 外部存储路径,需保证有写入权限
output_path = "/path/to/external/storage/target_data.bin"

connection = MySQLdb.connect(host='xxx', port='xxx', user='xxx', passwd='xxx', db='xxx')
with connection.cursor() as cursor:
    # 先查询目标BLOB的总长度
    cursor.execute("SELECT LENGTH(data) AS len FROM data_table WHERE id = %s", (target_id,))
    total_length = cursor.fetchone()[0]

    with open(output_path, "wb") as f:
        offset = 0
        while offset < total_length:
            # MySQL SUBSTRING函数偏移量从1开始,因此offset需要+1
            cursor.execute(
                "SELECT SUBSTRING(data, %s, %s) AS block FROM data_table WHERE id = %s",
                (offset + 1, BLOCK_SIZE, target_id)
            )
            block = cursor.fetchone()[0]
            f.write(block)
            offset += BLOCK_SIZE

该方案的优势是没有额外依赖,哪怕驱动版本较低也可正常运行,仅需多发起若干次查询,1GB数据按10MB拆分仅需100次查询,性能损耗极低。

方案2:流式游标读取(性能最优,仅需一次查询)

MySQL-python(mysqlclient)支持服务端流式游标SSCursor,开启后不会将全量查询结果缓存到客户端内存,而是从MySQL服务端流式拉取数据,拉取到的内容可直接写入外部存储,不会一次性占用大量内存。
示例代码如下:

import MySQLdb
from MySQLdb.cursors import SSCursor

target_id = 123
output_path = "/path/to/external/storage/target_data.bin"

connection = MySQLdb.connect(
    host='xxx', port='xxx', user='xxx', passwd='xxx', db='xxx',
    # 核心参数:不将全量结果缓存到客户端内存
    use_result=True
)
# 使用服务端流式游标
with connection.cursor(cursorclass=SSCursor) as cursor:
    cursor.execute("SELECT data FROM data_table WHERE id = %s", (target_id,))
    row = cursor.fetchone()
    with open(output_path, "wb") as f:
        f.write(row[0])

注意事项:流式游标读取结果的过程中,同一个连接不能执行其他查询,需等当前结果读取完毕后再执行其他操作。

方案3:服务端直接导出(适合无需客户端处理数据的场景)

如果你的外部存储是MySQL服务端可直接访问的共享存储,可直接使用MySQL原生的SELECT ... INTO DUMPFILE语法,直接将BLOB内容写入服务端的外部存储路径,完全不需要消耗客户端内存,性能最高。
示例SQL:

SELECT data INTO DUMPFILE '/shared_storage/target_data.bin' FROM data_table WHERE id = 123;

注意该语法要求写入的目标文件不存在,且运行MySQL进程的操作系统用户拥有目标目录的写入权限。

升级到MySQL 8.0的额外优化

如果可以升级到MySQL 8.0版本,针对大BLOB场景有额外性能优化:默认支持更大的最大传输数据包、BLOB传输内存开销更低,不过上述三个方案在MySQL 5.7版本下均可正常运行,非必须升级。

内容的提问来源于stack exchange,提问作者Yang Hanlin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 14:24:03