max_prepared_stmt_count 参数控制了一个 MySQL 实例能够准备的最大预处理语句(prepared statements)的数量。
预处理语句是一种优化技术,可以在应用程序发送sql语句到数据库之前先将其编译和缓存起来,以提高sql的执行效率以及防止sql注入。每个预处理语句都会占用一些内存资源,因此 MySQL 引入了 max_prepared_stmt_count 参数来限制其数量,以防止消耗过多的内存。当尝试创建的预处理语句数量超过了 max_prepared_stmt_count 参数的限制时,就会出现这个错误。
1、查看mysql当前值
show variables like 'max_prepared_stmt_count';
max_prepared_stmt_count 16382
2、分析
SHOW GLOBAL STATUS LIKE 'com_stmt%';
Com_stmt_execute 6555911 // prepare语句执行的次数
Com_stmt_close 903007 // prepare语句关闭的次数
Com_stmt_fetch 0
Com_stmt_prepare 928835 // prepare语句创建的次数
Com_stmt_reset 0
Com_stmt_send_long_data 0
Com_stmt_reprepare 611
Com_stmt_prepare 减去 Com_stmt_close 大于 max_prepared_stmt_count 可能就会出现这种错误。
3、临时解决方案
如果影响了线上业务,但无法马上定位到问题,可临时紧急手动调高max_prepared_stmt_count
set global max_prepared_stmt_count=100000;
4、最终解决方案
一般而言,默认值16382是足够用的。如果业务上并发未达到,那大概率是client端没有关闭prepared语句。定位分析具体的业务sql。
4.1 确认开启了performance_schema
SHOW VARIABLES LIKE 'performance_schema';
performance_schema ON
4.2 查看待执行的prepared sql
SELECT sql_text FROM prepared_statements_instances;
当前截图是正常的。出现问题时,待执行的prepared sql达到了1w+,进行分类统计后,未close的sql显而易见。
释放未使用的预处理语句:如果你的应用程序创建了很多预处理语句,但只使用其中的一部分,可以通过在应用程序中显式地关闭和释放未使用的预处理语句来减少已存在的预处理语句数量。在你不再需要使用某个预处理语句时,调用相应的释放方法将其关闭并释放相关资源。