MAX()和MIN()仅返回字段极值而非整行数据;需配合子查询、ORDER BY+LIMIT或窗口函数获取完整记录;分组查询中须遵守GROUP BY规则;索引优化依赖联合索引设计。

MAX() 和 MIN() 返回的是字段的极值,不是整行数据
很多人误以为 MAX() 或 MIN() 能直接拿到“销售额最高那条订单的全部信息”,结果只得到一个数字。这是因为这两个聚合函数只作用于单个列,返回该列的最大/最小值,不携带任何上下文(比如对应哪一行、其他字段是什么)。如果需要整行,得配合子查询或 ORDER BY + LIMIT。
用子查询获取极值所在完整记录时要注意 WHERE 条件匹配
常见写法是先用 SELECT MAX(price) FROM products 拿到最大值,再用这个值去查整行:SELECT * FROM products WHERE price = (SELECT MAX(price) FROM products)。但这里有个坑:如果有多个商品价格并列最高,会返回多行;如果字段允许 NULL,MAX() 忽略 NULL,但 WHERE price = ... 无法匹配 NULL 值,不会出错但可能漏数据。
- 确保比较字段非 NULL,或加
AND price IS NOT NULL - 若只要一条记录,改用
ORDER BY price DESC LIMIT 1更直观 -
MIN()同理,注意 ASC/LIMIT 1 的组合
GROUP BY 场景下 MAX/MIN 是按组计算,别和 SELECT * 混用
在分组查询中,MAX(created_at) 可以知道每类商品最新上架时间,但不能同时 SELECT *, MAX(created_at) —— MySQL 8.0+ 严格模式会报错 Expression #1 of SELECT list is not in GROUP BY clause。必须把所有非聚合字段都放进 GROUP BY,或者只选聚合结果。
- 正确写法:
SELECT category, MAX(price), MIN(price) FROM products GROUP BY category - 错误写法:
SELECT *, MAX(price) FROM products GROUP BY category(除非启用了sql_mode中的ONLY_FULL_GROUP_BY关闭) - 想查每组里最新一条完整记录?得用窗口函数
ROW_NUMBER() OVER (PARTITION BY category ORDER BY created_at DESC),不是 MAX/MIN 能解决的
性能上,有索引时 MAX/MIN 可走索引最左端,但别指望它加速复杂条件
如果对 price 建了索引,SELECT MAX(price) FROM products 很快——MySQL 直接取 B+ 树最右叶子节点。但加上 WHERE status = 'active' 后,除非索引是 (status, price) 这样的联合索引,否则无法利用索引快速定位极值,会退化为扫描。
- 单字段索引对带 WHERE 的极值查询帮助有限
- 高频执行的极值查询,优先考虑覆盖索引设计
-
MIN()和MAX()在同一个查询里同时用,不会额外开销,MySQL 一次扫描就能拿到两个值
实际业务里,极值往往只是中间步骤,真正要的是“谁最贵”“哪天最早”“哪个用户最近登录”。这时候 MAX/MIN 只是起点,后面大概率要接关联、子查询或窗口函数——别卡在函数本身,看清你要的到底是不是那个数字。


















