Python批量调用MySQL存储过程报错问题求助
解决方案
一、解决"Commands out of sync"错误
这个错误的核心原因是:调用存储过程后,MySQL会返回至少一个结果集(即使存储过程没有返回数据,也会返回一个空结果集标记执行完成),如果没有彻底读取/清理这些结果集就执行下一条语句,驱动就会抛出同步错误。
处理方式:执行存储过程后清理所有结果集
每次执行CALL语句后,循环读取所有结果集并切换到下一个,直到没有剩余结果集:
for stm in sql_stms: mycursor.execute(stm) # 仅针对存储过程调用处理结果集 if stm.strip().upper().startswith("CALL"): # 循环读取所有结果集并切换 while True: # 读取当前结果集(即使是空的) mycursor.fetchall() # 切换到下一个结果集,没有则退出循环 if not mycursor.nextset(): break
二、批量提交提升执行效率
频繁的commit是性能瓶颈的核心,因为每次提交都需要与MySQL服务器进行网络交互,开销极大。优化思路是减少提交次数,同时对可批量处理的语句使用批量执行API。
1. 分批次提交事务
将多个语句放入同一个事务,每N条语句提交一次,最后提交剩余语句:
batch_size = 50 # 根据业务调整批次大小 for idx, stm in enumerate(sql_stms): mycursor.execute(stm) # 处理存储过程结果集(同上) if stm.strip().upper().startswith("CALL"): while True: mycursor.fetchall() if not mycursor.nextset(): break # 达到批次大小则提交 if (idx + 1) % batch_size == 0: mydb.commit() # 提交剩余未批量的语句 mydb.commit()
2. 对同结构的DML语句使用executemany批量执行
对于结构相同的INSERT/UPDATE/DELETE语句,不要逐个执行,而是提取参数后用executemany批量执行,效率远高于循环execute:
# 示例:批量处理INSERT语句 insert_sql = "INSERT INTO your_table (col1, col2, col3) VALUES (%s, %s, %s)" insert_params = [] # 从sql_stms中筛选并提取INSERT语句的参数 for stm in sql_stms: if stm.strip().upper().startswith("INSERT"): # 这里需要根据实际语句解析参数,或者提前将参数与语句分离 # 假设已解析得到参数组 params = (val1, val2, val3) insert_params.append(params) # 批量执行 if insert_params: mycursor.executemany(insert_sql, insert_params) # 处理存储过程和其他语句 call_stms = [stm for stm in sql_stms if stm.strip().upper().startswith("CALL")] other_stms = [stm for stm in sql_stms if not stm.strip().upper().startswith("CALL") and not stm.strip().upper().startswith("INSERT")] for stm in other_stms + call_stms: mycursor.execute(stm) if stm.strip().upper().startswith("CALL"): while True: mycursor.fetchall() if not mycursor.nextset(): break # 最后统一提交 mydb.commit()
3. 合并存储过程调用为多语句执行
将多个CALL语句合并为一个带分号分隔的字符串,使用execute(stm, multi=True)执行,同时逐个处理每个调用的结果集:
# 筛选所有存储过程调用语句 call_stms = [stm for stm in sql_stms if stm.strip().upper().startswith("CALL")] other_stms = [stm for stm in sql_stms if not stm.strip().upper().startswith("CALL")] # 先执行非存储过程语句 for stm in other_stms: mycursor.execute(stm) # 合并并执行存储过程调用 if call_stms: combined_calls = "; ".join(call_stms) # 执行多语句,multi=True启用多结果集处理 for result in mycursor.execute(combined_calls, multi=True): # 读取结果集,避免同步错误 if result.with_rows: result.fetchall() # 统一提交 mydb.commit()
内容的提问来源于stack exchange,提问作者Mihael Manolov
相关产品推荐
相关产品推荐

