Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL存储过程未执行

MySQL存储过程未执行的问题排查过程

作者:一线大码

文章讲述了对 MySQL 存储过程未执行的问题排查过程,先后排查了数据库版本升级、用户权限不足,最终发现是存储过程创建时的 SQL 模式导致,即使之后去掉该模式,存储过程内部仍沿用旧模式,重新创建存储过程后问题解决,需要的朋友可以参考下

1. 问题背景

最近部署了一套测试环境,同事发现以前遗留的一个存储过程未运行,需要我帮忙排查下。下面说一下我的排查过程。列出每种可能得原因以及考虑。

2. 问题排查

2.1. 数据库版本升级的问题

之前我们用的是 8.0.x 版本的 MySQL,最近运维将数据库升级到了 8.4.3 版本。刚开始怀疑是数据库升级导致的,查了相关的版本说明,并没有发现会导致存储过程不执行的问题。

2.2. 用户权限不足的问题

检查了存储过程中定义的用户为root@%,并查看了权限,发现没有问题。

这里记录下涉及到的查询:

用户权限查询

确保执行存储过程的用户有足够的权限。你可以使用如下命令查看权限:

SHOW GRANTS FOR 'your_username'@'your_host';

并确保有 EXECUTE 和 ALTER ROUTINE 权限。如果没有,你可以通过以下命令授予权限:

GRANT EXECUTE, ALTER ROUTINE ON your_database_name.* TO 'your_username'@'your_host';

查询命令解析

SHOW GRANTS FOR `root`@`%`;

这条 SQL 命令在 MySQL 数据库中用来展示用户名为 root,且可以从任意主机(由%表示)连接到 MySQL 服务器的用户的权限。

如果在执行 SHOW GRANTS FOR 'root'@'%'; 后发现结果中缺少 EXECUTE 权限,表示 root 用户当前没有被授予执行存储过程或函数的权限。EXECUTE 权限是 MySQL 中用于执行存储过程和存储函数的权限。

可以使用 GRANT 语句为 root 用户添加 EXECUTE 权限:

GRANT EXECUTE ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;

这条命令做了以下几件事:

2.3. 存储过程本身的问题

首先这个存储过程在生产环境还有其他环境都是可以正常运行的。因为是复制过来的,所以一开始我就没想到这个错误。但是排查到这里后,还是使用CALL()去手动调度了一下该存储过程,竟然执行报错了,报错如下:

1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'Newton.imsi_transaction_cdr_raw_cn.carrier_id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

这下感觉终于有眉目了,这明显是 SQL 模式导致的问题。查看了下存储过程的语句,里面还真有GROUP BY,并且不符合ONLY_FULL_GROUP_BY模式的要求。存储过程未执行的原因找到了,我想着接下来去除掉该 SQL 模式应该就能解决问题了。

我赶紧去查了一下当前的全局 SQL 模式和当前会话 SQL 模式,傻眼了,SQL 模式中并没有ONLY_FULL_GROUP_BY模式,这时我想起来了,当时环境部署完后,我就要求运维将该ONLY_FULL_GROUP_BY模式去掉了,那为啥现在还会报这种错误,不应该啊,想不明白。

这里记录下 MySQL 查询 SQL 模式并去除 ONLY_FULL_GROUP_BY 的语句:

查询全局 SQL 模式,全局SQL模式影响所有新的会话(连接),但不影响已经存在的会话

SELECT @@GLOBAL.sql_mode;

查询当前会话SQL模式,当前会话 SQL 模式仅影响当前连接

SELECT @@SESSION.sql_mode;

或者,更简洁地:

SELECT @@sql_mode;

临时去除 ONLY_FULL_GROUP_BY(仅影响当前会话)

使用SET SESSION语句来更改当前会话的 SQL 模式:

SET SESSION sql_mode = REPLACE(@@SESSION.sql_mode, 'ONLY_FULL_GROUP_BY', '');

永久去除 ONLY_FULL_GROUP_BY(影响所有新会话)

要永久更改全局 SQL 模式,需要编辑 MySQL 的配置文件(如my.cnfmy.ini),然后重启 MySQL 服务。但是,直接修改全局 SQL 模式可能会影响其他用户和应用,因此通常建议只在必要时进行此类更改。

操作步骤:

例如,配置文件中的设置可能如下所示:

[mysqld]
sql_mode = "STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,...(其他模式,但不包括ONLY_FULL_GROUP_BY)"

3. 问题解决

目前情况是 MySQL 8.4.3 版本,我明明之前已经去掉了 ONLY_FULL_GROUP_BY 模式,为什么调用存储的时候还会报 1055 的错误?

错误提示很明显,肯定是 ONLY_FULL_GROUP_BY 模式导致的,现在就是要找到为什么明明没有该模式,怎么还会报这个错误。

在网上查资料的过程中,就在百思不解的时候,不经意看到了一处说明:

‌存储过程内部的 sql_mode‌:存储过程在创建时可能会捕获当前的 sql_mode 设置,并在每次执行时使用该设置。如果存储过程是在 ONLY_FULL_GROUP_BY 模式启用时创建的,那么即使你在之后禁用了该模式,存储过程内部仍然可能使用旧的 sql_mode。要解决这个问题,需要重新创建存储过程,确保在创建时 ONLY_FULL_GROUP_BY 模式是禁用的。

好吧,问题明朗了,当时是这样的,运维那边创建好数据库后,我进行库表和存储过程的初始化,服务部署后,通过服务日志发现有GROUP BY报错,才找的运维去掉了 ONLY_FULL_GROUP_BY 模式,也就是说存储过程创建的时候,数据库的 SQL 模式中是含有 ONLY_FULL_GROUP_BY 模式的。所以存储过程内部的 sql_mode‌ 肯定也是含有 ONLY_FULL_GROUP_BY 模式的,所以会报 1055 错误。

那解决办法就很简单了,删除掉当前的存储过程,重新创建即可,我试了下,重新创建后,手动调用了下,果然正常执行了。至此,问题解决!

以上就是MySQL存储过程未执行的问题排查过程的详细内容,更多关于MySQL存储过程未执行的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文