Typography

一只奶牛猫

MySQL ONLY_FULL_GROUP_BY模式配置与SQL优化指南

发布于 # database

某天,生产报错,故搜索原因。

image.png 得到数据库重启,原来的配置文件不生效了,即sql_mode标准化。

ONLY_FULL_GROUP_BY官方说明: Reject queries for which the select list, HAVING condition, or ORDER BY list refer to nonaggregated columns that are neither named in the GROUP BY clause nor are functionally dependent on (uniquely determined by) GROUP BY columns.

拒绝选择列表、 HAVING条件或ORDER BY列表引用非聚合列的查询,这些列既不在GROUP BY子句中命名,也不在功能上依赖于(唯一确定的) GROUP BY列。(谷歌翻译)

原因分析

假设你安装的是MySql 5.7以后的版本,比如5.7.21,默认情况下,sql_mode里的only_full_group_by是被打开的:

select version();

select @@GLOBAL.sql_mode;

因为是老项目,可能之前项目中的某些sql书写并不规范。

解决方法

1.命令行更改数据库的sqlMode

命令更改

SET @@SESSION.sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
SET @@SESSION.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';

注意事项:如果仍然报错,请打开新会话执行查询语句。

还要值得注意的是,上面关闭only_full_group_by的方式是临时的,如果重启了MySql服务器,only_full_group_by又被打开了.

2.修改配置文件

可以通过在/etc/my.cnf文件添加以下内容,来永久关闭only_full_group_by:

sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

修改完毕后,记得重启MySql。

如果重启后也不会生效,检查下sql_mode的位置是不是不对(放在最后是不会生效的):

image.png

3.重构问题代码

SELECT column1, column2, SUM(column3)
FROM your_table
GROUP BY column1, column2;

遇到稍微复杂的查询参考

SELECT
  CASE
    WHEN zd.order_type = 0 THEN zp.supplier_id
    ELSE msup.supplier_id
  END AS supplierId,
  SUM(sales_amount) AS totalSales
FROM
  your_table
GROUP BY
  CASE
    WHEN zd.order_type = 0 THEN zp.supplier_id
    ELSE msup.supplier_id
  END;
SELECT column1, column2, MAX(column3)
FROM your_table
GROUP BY column1, column2;

聚合函数包括SUM(),MIN(),MAX(),AVG(),COUNT(),GROUP_CONCAT

SELECT column1, column2, ANY_VALUE(column3)
FROM your_table
GROUP BY column1, column2;