MySQL RDS存储过程二次执行后连接丢失问题排查求助
从你遇到的问题和提供的崩溃日志、存储过程代码来看,连接丢失的根源是MySQL服务端进程崩溃,而崩溃的触发点和存储过程中的WITH ROLLUP语法直接相关,大概率是MySQL的一个已知bug。
关键日志信息解读
崩溃日志里的核心线索:
pure virtual method called terminate called without an active exception
以及调用栈中的is_rollup_group_wrapper、change_to_use_tmp_fields_except_sums等函数,指向ROLLUP相关的代码路径在第二次执行存储过程时出现了对象生命周期错误——存储过程第一次执行后,某些ROLLUP相关的临时对象没有被正确清理,第二次执行时调用了已经析构的虚函数,直接导致mysqld进程崩溃,进而触发Error Code: 2013连接丢失错误。
另外你提到“将存储过程的代码复制为独立查询执行时可多次运行正常”,这是因为独立查询每次都会重新初始化查询上下文,不会复用存储过程会话中的残留对象。
验证与测试建议
移除
WITH ROLLUP验证
修改存储过程,去掉GROUP BY后的WITH ROLLUP,然后多次调用该存储过程。如果连接丢失问题消失,即可确认是ROLLUP语法在存储过程复用场景下的bug。改用动态SQL测试
尝试将存储过程改为动态SQL形式,强制每次调用重新生成查询计划,避免复用会话中的残留对象。示例代码如下:CREATE PROCEDURE `test`( IN id INT(11) ) BEGIN SET @sql = CONCAT( 'WITH roster_players AS ( SELECT p.player_id FROM players p JOIN bridge_player b ON p.player_id = b.player_id WHERE b.player_id = ', id, '), player_games AS ( SELECT DISTINCT b.game_id FROM batters b JOIN games g ON b.game_id = g.game_id JOIN roster_players rp ON b.batter_id = rp.player_id) SELECT b.batter_id, bip_location, COUNT(*) AS zone_cnt FROM batters b JOIN player_games g ON b.game_id = g.game_id JOIN roster_players rp ON b.batter_id = rp.player_id GROUP BY bip_location , b.batter_id WITH ROLLUP;' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END测试多次调用该修改后的存储过程,看是否还会出现连接丢失。
会话隔离测试
在第一次调用存储过程后,显式断开当前连接,重新建立连接后再次调用。如果新连接下第二次调用正常,说明问题是会话级别的资源泄漏导致的,进一步佐证ROLLUP相关对象未被正确清理的推测。
临时解决方案与长期修复
- 临时规避:如果业务允许,暂时移除
WITH ROLLUP,改用应用层计算汇总数据;或者使用动态SQL的方式绕过会话对象复用问题。 - 版本升级:检查你的AWS RDS MySQL版本,这个bug在MySQL 5.7/8.0的早期版本中较为常见,升级到对应大版本的最新小版本(比如MySQL 8.0.30+)通常会修复这类ROLLUP相关的崩溃问题。记得先在测试环境验证升级兼容性。
- 联系AWS支持:如果升级不可行,可以提交AWS支持工单,提供崩溃日志和存储过程代码,让他们确认是否是RDS特定版本的已知问题,获取针对性的补丁或解决方案。
内容的提问来源于stack exchange,提问作者rahlf23

