首页/数据/SQL 速查/MIN / MAX 最值统计
聚合与窗口函数54 条

MIN / MAX 最值统计

取列的极小值与极大值;忽略 NULL,可用于时间范围、价格区间等场景,配合 GROUP BY 得到分组极值。

SQL 速查数据更新于 2026-10-13

MIN / MAX 是什么

MIN 与 MAX 是取列最值的聚合函数,计算时忽略 NULL,只有在没有任何非 NULL 值时才返回 NULL。它们是最容易走索引优化的聚合:列上有 B 树索引时,MySQL 与 PostgreSQL 都可以直接读索引的一端,拿到值即返回,不必扫描全表——这是 MIN/MAX 与 SUM/AVG 的关键区别。带 WHERE 条件时能否免扫描,取决于索引是否同时覆盖过滤列与最值列。

基本信息

适用平台MySQL 8.0 / PostgreSQL / SQL Server / Oracle
NULL 处理忽略 NULL 参与计算;所有值都为 NULL 时返回 NULL
索引优化无 WHERE 且列上有索引时可直接读索引端点,MySQL 计划中显示为 Select tables optimized away
返回类型与输入列同类型;字符串按排序规则比较
与窗口函数区别MAX(col) OVER (…) 不折叠行,聚合 MAX(col) 把多行折成一行

典型使用场景

  • 报表取区间:最早与最晚时间、最低与最高价格
  • 找最新一条记录:MAX(created_at) 定位时间边界
  • 数据校验:检查数值是否越界、时间是否超出合理区间
  • 分组统计:每组的最低最高价,用于定价与异常检测
  • 增量抽取:用 MAX(id) 或 MAX(updated_at) 记录上次同步位置

基础用法

基础用法
SELECT MIN(created_at) AS first_order,     # 最早一单
       MAX(created_at) AS last_order       # 最新一单
FROM orders
WHERE user_id = 42;                         # 复合索引 (user_id, created_at) 时可直接定位

SELECT category, MIN(price) AS low_price, MAX(price) AS high_price
FROM products
GROUP BY category;                          # 每组的最值

SELECT MAX(amount) FROM orders;             # 无 WHERE 时可直接读索引末端

同一行同时取最值

同一行同时取最值
-- 一次扫描同时算出 MIN 与 MAX,避免两次全表扫描
SELECT MIN(amount) AS low, MAX(amount) AS high, COUNT(*) AS cnt
FROM orders
WHERE created_at >= '2026-01-01';

-- 需要「最值所在的那一行」时,MIN/MAX 不够,要用排序或窗口函数
SELECT id, amount FROM orders ORDER BY amount DESC, id DESC LIMIT 1;

SELECT id, amount FROM (
  SELECT id, amount, ROW_NUMBER() OVER (ORDER BY amount DESC, id DESC) AS rn
  FROM orders
) t WHERE rn = 1;

计划信号读法

计划提示含义处理方向
Extra 显示 Select tables optimized away直接读索引求最值正常,无需优化
type 为 ALL 且 rows 很大退化为全表扫描检查是否有匹配的复合索引
MIN/MAX 返回 NULL没有匹配行,或该列全为 NULL业务上区分「无数据」与「值为空」
GROUP BY 后每组最值很慢需要逐组定位考虑窗口函数或预聚合汇总表
聚合函数忽略 NULL,这一点与 COUNT 系列不同:列里混有 NULL 时 MIN/MAX 结果不受影响,但 COUNT(col) 会少算这些行,做口径对比时要一起对齐。
用 MAX(id) 当「最新一条」只适用于 id 单调递增、没有历史数据回填的场景;按时间取最新应用 MAX(created_at),并注意同一时间存在多条记录时还需要次级排序键。

易错点

  • 以为 MIN/MAX 一定扫全表:无 WHERE 且列有索引时通常直接读索引端点
  • 拿 MAX(id) 当最新记录,id 与业务时间不一致时会取错行
  • 空表时 MIN/MAX 返回 NULL,却被当成 0 参与后续计算
  • 分组场景对每组分别执行一次 MIN 与一次 MAX,白扫两遍数据

数据来源与参考

  • MySQL 8.0 Reference Manual · MIN / MAX
  • PostgreSQL Documentation · Aggregate Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌