简短回答
这是一个速度优化技巧
默认情况下启用了该设置,但可以通过此设置禁用:https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html
详细回答
非标准的简写group by子句之所以存在是为了提高速度。
MySQL允许程序员确定所选字段是否在group by子句上具有功能依赖性。
数据库不进行任何测试,只是选择找到的第一个结果作为字段的值。
这样可以大大提高速度。
考虑以下代码:
SELECT f1, f2, f3, f4 FROM t1 GROUP BY f2
-- invalid in most SQL flavors, valid in MySQL
MySQL只会选择它找到的第一个值,花费最少的时间。
f1、f3、f4将来自同一行,但如果涉及多个表和连接,这种关系将会破裂。
为了在SQL Server中做类似的事情,你需要做一些操作。
SELECT MIN(f1), f2, MIN(f3), MIN(f4) FROM t1 GROUP BY f2
-- valid SQL, but really a hack
数据库现在必须检查所有的结果来找到最小值,费力地忙碌着。
f1、f3、f4很可能彼此之间没有关联,并且不会来自同一行。
然而,如果你这样做:
SELECT id as `primary_key`, count(*) as rowcount, count(f2) as f2count, f2, f3, f4
FROM t1
GROUP BY id
其余的字段都将在id上具有功能依赖关系。
Rowcount始终为1,f2count要么为0(如果f2为空),要么为1。
在连接操作中,涉及许多表的情况下,如下所示:
例如:
网站1 -> n 主题1 -> n 线程1 -> n 帖子1 -> 1 个人。
如果你进行一个涉及所有表格的复杂查询,并且只对posts.id进行GROUP BY,那么很明显,所有其他字段都对posts.id具有功能依赖关系(而且仅对posts.id)。
因此,在GROUP BY子句中列出更多字段或者强制使用聚合函数是没有意义的。
为了加快速度,MySQL不会强制你这样做。
但是,你需要理解功能依赖的概念以及表中的关系和你编写的连接,这给程序员带来了一定的负担。
然而,使用:
SELECT
posts.id, MIN(posts.f2)
,MIN(threads.id), min(threads.other)
,MIN(topics.id), ....
,MIN(website.id), .....
,MIN(Person.id), ...
FROM posts p
INNER JOIN threads t on (p.thread_id = t.id)
INNER JOIN topic to on (t.topic_id = to.id)
INNER JOIN website w ON (w.id = to.website_id)
INNER JOIN person pe ON (pe.id = p.person_id)
GROUP BY posts.id //NEVER MIND THE SYNTAX ERROR WITH THE ALIASES
对程序员来说,完全给予了相同的心理负担。
