面试复盘之WHERE和HAVING的区别以及MySQL的索引

WHERE关键字

WHERE的作用

  • where是在数据分组之前进行过滤
  • 执行流程
text 复制代码
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
  • 示例
sql 复制代码
SELECT * 
FROM employee
WHERE salary > 5000;
  • 含义:先从表中筛选出 salary > 5000 的记录,再返回结果。

HAVING 关键字

HAVING 的作用

  • HAVING 是在分组之后对聚合结果进行过滤。
  • 示例:
sql 复制代码
SELECT dept, COUNT(*)
FROM employee
GROUP BY dept
HAVING COUNT(*) > 2;

执行逻辑:先按 dept 分组,计算每组 COUNT(*),再过滤 COUNT(*) > 2

WHERE 和 HAVING 的区别

  • WHERE 和 HAVING 都是 SQL 中的过滤条件,但它们的作用阶段不同。
区别 WHERE HAVING
作用阶段 分组前过滤 分组后过滤
是否可以使用聚合函数 不可以 可以
是否必须配合 GROUP BY 不需要 一般需要

为什么 HAVING 需要和 GROUP BY 使用

  • 因为 HAVING 的作用是过滤聚合结果,而聚合结果只有在分组之后才会产生。
  • 常见的聚合函数:
sql 复制代码
count(*) sum() max() min() AVG() 
  • 这些聚合函数必须在分组后才有意义。
  • 执行流程:
text 复制代码
1 FROM        找到表
2 WHERE       过滤行数据
3 GROUP BY    分组
4 聚合函数计算
5 HAVING      过滤分组结果
6 SELECT
7 ORDER BY
  • 因此 WHERE 过滤原始数据,HAVING 过滤聚合后的数据

什么时候用 WHERE,什么时候用 HAVING

  • 原则:能用 WHERE 就不要用 HAVING。
  • 原因:WHERE 在分组前过滤,数据量更少,效率更高。
  • 举例:
sql 复制代码
SELECT dept, COUNT(*)
FROM employee
WHERE salary > 5000
GROUP BY dept
HAVING COUNT(*) > 2;
  • 执行逻辑:
  1. WHERE 先过滤工资 > 5000 的员工
  2. GROUP BY 再分组
  3. HAVING 再过滤部门人数
  • 这样效率更高。

MySQL 的索引

  • 索引是 MySQL 中提升查询效率的核心工具,可以把它理解成书籍的目录------ 没有目录时找内容要逐页翻(全表扫描),有目录时能直接定位到目标页码(快速查询)。

索引的核心作用

  1. 加速查询:这是最核心的作用,避免全表扫描,直接定位符合条件的数据。
  2. 优化排序/分组:对需要 ORDER BY/GROUP BY 的字段建索引,可避免临时表排序,提升效率。
  3. 唯一约束:如主键索引、唯一索引,能保证字段值的唯一性(比如用户手机号不能重复)。
  • 注意:索引会降低插入/更新/删除的效率(因为修改数据时要同步维护索引),所以不是索引越多越好,按需创建即可。

索引的分类

  • 功能分类:主键索引、唯一索引、全文索引、普通索引
  • 数据结构分类:b+树索引、哈希索引
  • 存储位置分类:聚簇索引、非聚簇索引
索引类型 特点 适用场景
主键索引(PRIMARY KEY) 唯一、非空,一张表只能有 1 个主键索引 表的唯一标识(如用户 ID)
唯一索引(UNIQUE) 唯一,但允许 NULL(多个 NULL 不冲突),一张表可创建多个 唯一标识字段(如手机号、邮箱)
普通索引(INDEX) 无唯一性约束,最常用 普通查询字段(如商品名称、分类)
组合索引(复合索引) 基于多个字段的索引,遵循最左前缀原则 多字段联合查询(如 WHERE 分类=1 AND 价格<100)
全文索引(FULLTEXT) 针对文本内容的模糊匹配优化(如文章内容搜索),仅支持 MyISAM/InnoDB(5.6+),适用于 CHAR、VARCHAR 和 TEXT 等字段。 长文本模糊查询(如 MATCH(content) AGAINST('关键词'))
  • 主键索引=唯一索引+非空。每个表只能有一个主键索引,但可以有多个唯一索引。
  • 普通索引仅用于加速查询,不限制字段值的唯一性;适用于高频写入的字段、范围查询的字段。
  • 唯一索引强制字段值的唯一性,插入或更新时会触发唯一性检查;适用于业务唯一性约束的字段、防止数据重复插入的字段。

索引的底层结构

  • MySQL 中绝大多数索引(主键、唯一、普通、组合)的底层是B+树
  • B+ 树特点:
    • 所有数据都存在叶子节点,且叶子节点按顺序连成链表(方便范围查询,如 WHERE id BETWEEN 10 AND 20);
    • 非叶子节点只存索引值,不存数据,能让索引树更"矮胖",减少磁盘 IO 次数。
  • 对比哈希索引:
    • 哈希索引(Memory 引擎支持)查询等值快,但不支持范围查询、排序,而B+树索引完全支持。

常见的索引失效场景

  • 违反最左前缀原则:组合索引 (a,b,c),查询时只用 b/c、或 b,c,索引失效(必须从最左的 a 开始用)。
  • 字段做函数/运算:如 WHERE SUBSTR(phone,1,3)='138'、WHERE id+1=10,索引失效。
  • 使用模糊查询前缀 %:WHERE name LIKE '%张三' 失效,WHERE name LIKE '张三%' 有效。
  • 字段类型不匹配:如 phone 是 VARCHAR 类型,查询时写 WHERE phone=13800138000(数字),索引失效。
  • 使用OR连接非索引字段:如 WHERE name='张三' OR age=20(age 无索引),索引失效。