问题
白天收到一个慢查询的告警,发现了一个很奇特的语句,简化后,摘要如下:
SELECT c.`name`,NOW(),COUNT(1) 'FROM `order` o
LEFT JOIN `shop` c ON o.`ShopId`=c.`shopId`
WHERE o.`STATUS`IN('L')
GROUP BY o.`ShopId`
当前数据库版本为5.7.19,sql_mode为 ONLY_FULL_GROUP_BY,如有不同情况,请以实际环境为准
有经验的朋友,大概一眼就会发现问题所在,在ONLY_FULL_GROUP_BY的严格模式下,select 查询列未包含在group by的子句中,该语句应当会执行出错,抛出错误如:
1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'order.ShopId' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
但实际该语句仍旧能够跑成功,问题出在哪儿?查询表结构后发现了端倪:
desc order
Field Type Null Key Default Extra
shopId char(15) NO PRI
...
order表中shopid为主键;
实验
那么构造一个类似的表进行试验:
create table testa
(id int primary key auto_increment,
name varchar(10) unique key ,
statu varchar(10)
);
insert into testa (name,statu) values ('a','Y');
insert into testa (name,statu) values ('b','Y');
insert into testa (name,statu) values ('c','Y');
insert into testa (name,statu) values ('d','Y');
insert into testa (name,statu) values ('e','Y');
insert into testa (name,statu) values ('f','Y');
select statu,count(1) from testa
group by id;
以上语句能够执行成功,翻阅官网相关文档:
提到sql1999规范中,如果custid是主键,则允许这种聚合;
总结
oracle或者sql server中如上语句执行会异常,mysql兼容了group by主键这种特殊情况,实际情况下,还是建议按照严格的逻辑去写聚合语句,毕竟按照主键分组,如果主键与查询列不是一对一的关系,可能最终聚合出来的结果和实际需要的就会产生差距。
参考文档: