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

使用Quota Guard从Python3写入MySQL时频繁遇通信包读取错误求助

批量写入MySQL连接丢失问题的优化经验总结

问题背景

我们每日运行若干部署在PythonAnywhere上的Python3脚本,通过Quota Guard(qgtunnel)向MySQL写入数据。数据量每日波动,数据量较大时频繁出现以下错误:

  • Python端报错:
    pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query')
    
  • MySQL端日志:
    2022-08-17T17:40:39.754094Z 77949 [Note] Aborted connection 77949 to db: 'db' user: 'user' host: 'IP' (Got an error reading communication packets)
    

原代码逻辑为每处理1000条记录提交事务、休眠6秒并重置数据库连接,但仍频繁报错。MySQL版本为5.7.25,相关配置:

max_allowed_packet: 1073741824
interactive_timeout: 31536000
wait_timeout: 31536000
connect_timeout: 31536000

按照@Rick James的建议改用executemany后错误消失,现总结类似场景的优化经验:

核心优化建议

  • 优先用批量操作替代单条循环写入:
    单条循环执行SQL会产生大量网络交互,尤其通过Quota Guard这类代理连接时,频繁的数据包传输更容易触发连接中断。executemany将多条操作打包发送,大幅减少网络请求次数,直接降低连接异常概率。
  • 合理控制批量大小:
    不是批量越大越好,需根据单条记录大小调整。比如单条记录较大时,可将批量数从1000下调至500或200,避免单批次数据包过大触发代理层隐性限制(即使MySQL的max_allowed_packet配置足够)。
  • 调整连接复用策略:
    原逻辑中每批次重置连接反而增加了连接建立的开销和风险。改用批量操作后,可保持连接复用,仅在捕获到OperationalError这类连接异常时再重新建立连接,无需主动休眠和重置。
  • 适配代理层超时配置:
    通过Quota Guard代理时,需确认代理的超时规则,避免代理主动断开长时间空闲的连接。如果批量操作间隔较长,可在间隔期发送SELECT 1这类简单心跳查询维持连接。
  • 添加异常重试机制:
    即使做了上述优化,仍可能因网络波动出现连接问题。建议给数据库操作添加重试逻辑,捕获2013这类连接错误时,重试2-3次后再抛出异常,提升脚本稳定性。

代码优化示例参考

原单条写入逻辑(简化版)

import pymysql
import time

conn = pymysql.connect(host='xxx', user='xxx', password='xxx', db='xxx')
cursor = conn.cursor()

records = get_records()  # 获取待写入数据
count = 0
for record in records:
    sql = "INSERT INTO table (col1, col2) VALUES (%s, %s)"
    cursor.execute(sql, (record['col1'], record['col2']))
    count += 1
    if count % 1000 == 0:
        conn.commit()
        time.sleep(6)
        # 重置连接
        cursor.close()
        conn.close()
        conn = pymysql.connect(host='xxx', user='xxx', password='xxx', db='xxx')
        cursor = conn.cursor()
conn.commit()
cursor.close()
conn.close()

优化后executemany逻辑(简化版)

import pymysql
from tenacity import retry, stop_after_attempt, retry_if_exception_type

@retry(stop=stop_after_attempt(3), retry=retry_if_exception_type(pymysql.err.OperationalError))
def batch_insert(conn, records):
    cursor = conn.cursor()
    sql = "INSERT INTO table (col1, col2) VALUES (%s, %s)"
    data = [(r['col1'], r['col2']) for r in records]
    cursor.executemany(sql, data)
    conn.commit()
    cursor.close()

def main():
    conn = pymysql.connect(host='xxx', user='xxx', password='xxx', db='xxx')
    records = get_records()
    batch_size = 1000
    # 分批次处理
    for i in range(0, len(records), batch_size):
        batch = records[i:i+batch_size]
        try:
            batch_insert(conn, batch)
        except Exception as e:
            # 记录失败批次并尝试重连
            print(f"Batch {i//batch_size} failed: {e}")
            conn.close()
            conn = pymysql.connect(host='xxx', user='xxx', password='xxx', db='xxx')
    conn.close()

if __name__ == "__main__":
    main()

内容的提问来源于stack exchange,提问作者Andrew Kloos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 00:18:24