MySql5.7的only_full_group_by

前言

好久没搞mysql web项目了, 记得上一次写mysql项目还是用的mysql5.6, 秉着新项目要用新版本的原则选择了mysql8.0, 逛了一圈mysql官网, 发现8.0收费, 果断告辞, 选择了免费里面的新版mysql5.7, 趟坑从这就开始了

项目报错

[Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column list which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

提取错误关键字only_full_group_by, 隐约记得使用mysql5.6的时候没见过这个错误

image.png

将错误贴到百度得到的答案都是教你怎么解决这个错误, 没说为什么会出现这个错误, 秉着存在即合理的态度, 奇特意研究了一下mysql为什么要加入only_full_group_by这个sql_mode模式

取经之路

看上去这种模式的出现完全是画蛇添足。事实上mysql更新这种模式不是没有意义的: 对于语义限制都比较严谨的多家数据库, 如sqlserver、oracle等数据库都不支持select target list中出现语义不明确的列, 这样的语句在这些数据库中是会被报错的, 所以从mysql5.7版本开始修正了这个语义, 就是所说的only_full_group_by语义。

在我遇到这种报错的情况中, 最多的就是分组求最值 ,例如:

select id,ename,max(sal) from e group by id
复制代码

求各部门最高的工资, 其中: id:部门, ename:名字, sal: 工资。或者是这种投机的表示方式:

select id,ename,sal from( select * from e order by sal desc ) t group by id
复制代码

而之后的版本不再支持了, 原因个人认为是消除了子查询的排序作用。而且官方也支持这个判断bugs.mysql.com/bug.php?id=…

如果在不关闭only_full_group_by模式的条件下, 是否有速度类似同时又符合规则的办法呢? 答案是存在的:

select id ,ename,sal from e, (select id ,max(sal) as maxsal from e group by id ) as t 
where e.id = t.id and e.sal = t.maxsal
复制代码

不需要用到两表联查, 性能也很好。
要适应only_full_group_by的出现我们就要对我们的sql语句进行多多思考。如果不想做出改变, 也可以选择暴力拆除。

暴力拆除

方法一 :

临时对mysql的sql_mode模式进行调整, 重启失效。
1、查看sql_mode

select @@sql_mode
复制代码

查询出来的值为: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

2、去掉ONLY_FULL_GROUP_BY,重新设置值。

set @@sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,
NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
复制代码

3、上面是改变了全局sql_mode,对于新建的数据库有效。对于已存在的数据库,则需要在对应的数据下执行:

set sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,
NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
复制代码

方法二 :

在my.cnf 里面[mysqld]下设置

sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,
NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
复制代码

在sql_mode 中去掉only_full_group_by, 保存后重启mysql。

附赠一个mysql的docker启动命令

docker run -p 3306:3306 --name mysql-5.7 --restart=always -m 2g \
-v /mnt/data/logs/mysql/logs:/var/log/mysql \
-v /mnt/data/docker/config/mysql/data:/var/lib/mysql \
-v /mnt/data/docker/config/mysql/conf:/etc/mysql \
-v /etc/localtime:/etc/localtime:ro \
-e MYSQL_ROOT_PASSWORD=mysql \
-d mysql:5.7
复制代码

如果你的数据库需要进行每天备份, 可以在服务器中创建一个shell脚本内容为:

#!/bin/bash  
docker exec api-mysql-5.7 /bin/bash -c '/usr/bin/mysqldump -uroot -pmysql db_test> 
"/var/log/mysql/db_test_`date +%Y%m%d%H%M%S`.sql"'
复制代码

编辑服务器定时器
crontab -e
设置每日1点进行数据库备份
0 1 * * * /mnt/data/docker/config/mysql/conf/databasebk.sh
定时器编辑成功后等待脚本运行结果。
注意:因为我们的脚本是凌晨一点执行, 所以请各位想第一时间看结果的朋友们注意保护头发

only_full_group_by的问题解决了, 文章也结束了, 在趟坑的路上大家也要多注意头发。

おすすめ

転載: juejin.im/post/7049973281339899935