在Mysql里,一般情况下,对一个排序后的查询进行分组,其排序会失效,只会根据数据库默认的排序方式(按插入顺序)得到查询结果,然后进行分组。

举个例子:
假设有一张用户登录记录表userLoginLog,里面记录了用户每次登录的时间。

名称

字段

用户id

id

用户名

name

登录时间

loginDate

现在想从这张表里查询出每个用户的第一次登录时间。
实现的方法有多种,这里不一一赘述。

这里只说一种方式:

  1. 先按时间倒叙
  2. 将1的结果根据用户id分组,这样按时间倒叙的第一条记录就会作为分组的记录。
select t.id, t.name, t.loginDate 
from (
	select id, name, loginDate 
	from userLoginLog 
	order by loginDate ASC
) t 
group by t.id

很简单直接的逻辑,但是现实并不总是如愿。
在实际查询的时候,分组展示的那条数据并不是排序后的第一条数据,而是数据库默认排序(即按插入顺序排序)的第一条数据。

这时候,只要在子查询里面加入limit,限制查询数量,就可以在分组的时候使用到我们自定义的排序了。

select t.id, t.name, t.loginDate 
from (
	select id, name, loginDate 
	from userLoginLog 
	order by loginDate ASC
	limit 9999999 			--加入限制
) t 
group by t.id

究其原因,是mysql在执行sql语句的时候,会先调用自身的 查询优化器 先对查询语句进行优化,再执行。在我们原来的子查询里面,查询优化器就对其进行了优化,丢弃了排序关键字,使用了默认排序方式,以提高查询效率。
而后面加入了limit关键字,限制了查询长度后, 查询优化器 辨识到子查询加入了更多的限制,在保留limit的同时,也保留了排序的要求。

注:

这里借用一张图,来解释mysql对语句的执行过程:

MySQL 排序并分页 mysql排序后分组_查询优化


顺带复习一下MySQL的关键字执行顺序

  1. from
  2. on
  3. join
  4. where
  5. group by
  6. 聚合函数,如:avg,sum…
  7. having
  8. select
  9. distinct
  10. order by
  11. limit

按照上面的顺序,可以发现一个规律,就是sql语句的执行顺序,是按照从大到小的范围来执行,层层筛选,最后得到所要的数据的。

  1. (1~3)获取范围:收集查询所需的所有表格。
  2. (4~7)第一步筛选:对表格内容做各种条件限制,得到符合查询要求的数据集合。
  3. (8)第二步筛选,出初步结果:在所得数据集合之上,进一步挑选所需字段,缩小查询范围。
  4. (9~10)优化内容:对最后查询出来的数据集合和字段,进行内容上的优化
  5. (11)按量输出:按要求输出所需数据量