索引使用与 SQL 优化
021 对于复合索引 (a, b, c),哪种条件组合通常能利用该索引的最左前缀?
难度: 基础
- A. WHERE a = 1 AND b = 2(连续使用前两列)
- B. WHERE b = 2 AND c = 3(跳过前导列 a)
- C. WHERE c = 3(完全不使用前导列)
- D. WHERE b BETWEEN 1 AND 3(以中间列开头)
查看答案与解析
正确答案A
正确原因: 最左前缀要求从第一列开始连续匹配,只有 WHERE a 加 b 连续使用前两列才能命中索引前缀。
关键边界: 跳过前导列或只使用后列时,该复合索引通常无法用于定位,可能退化为扫描。
错误选项辨析: 三种错误写法都跳过了前导列 a,无法利用该复合索引的顺序结构。
022 对索引列直接使用函数(如 WHERE DATE(created_at) = ?)会导致什么?
难度: 基础
- A. 无法直接利用该列索引,通常退化为全表扫描,除非建函数索引
- B. 一定更快,因为函数能压缩索引体积
- C. 只影响写入性能,不影响查询计划
- D. MySQL 会自动把函数改写为可索引的等值形式
查看答案与解析
正确答案A
正确原因: 对列做函数运算会破坏索引键的等值与有序匹配前提,优化器无法直接使用该列索引。
关键边界: MySQL 8.0 支持对表达式建立函数索引,才能覆盖此类查询。
错误选项辨析: 函数不会压缩索引,不影响写入,MySQL 也不会自动改写为可索引形式。
023 字符串列 phone 上建有索引,执行 WHERE phone = 13800138000(数字字面量)会发生什么?
难度: 基础
- A. 完全等价于字符串匹配,索引照常使用
- B. 触发隐式类型转换,把字符串列转为数字比较,通常导致索引失效
- C. MySQL 会直接报错拒绝执行
- D. 只有 PostgreSQL 有隐式转换,MySQL 不会做
查看答案与解析
正确答案B
正确原因: 比较时类型不一致会发生隐式转换,对索引列套上转换后无法直接走索引。
关键边界: 应传入字符串字面量或在应用层统一类型,避免依赖隐式转换。
错误选项辨析: 隐式转换会改变执行计划,MySQL 不会报错,隐式转换是各数据库常见的类型处理机制。
024 LIKE 查询中哪种写法最可能用到索引?
难度: 基础
- A. LIKE ‘%abc’(后缀匹配)
- B. LIKE ‘abc%‘(前缀匹配)
- C. LIKE ‘%abc%‘(中间匹配)
- D. LIKE ‘_abc’(通配符位于首字符)
查看答案与解析
正确答案B
正确原因: 前缀匹配保持了索引的有序性,优化器可沿索引定位起始位置。
关键边界: 后缀或中间匹配无法确定起点,通常只能全表扫描。
错误选项辨析: 三种错误写法都让通配符出现在开头,破坏了索引的定位能力。
025 EXPLAIN 结果中 type = ALL 表示什么?
难度: 基础
- A. 查询结果包含了所有列
- B. 索引把所有行都覆盖了,性能最好
- C. 全表扫描,未使用索引定位,通常需要优化
- D. 只读取了表的前 100 行
查看答案与解析
正确答案C
正确原因: type 列表示访问类型,ALL 即全表扫描,是访问方式而非结果集描述。
关键边界: 小表或低选择性条件下全表扫描可能反而合理,需结合 rows 估算判断。
错误选项辨析: 覆盖所有列是 Extra 中的 Using index,结果行数与 ALL 无关,ALL 也不代表行数上限。
026 EXPLAIN 的 key 列表示什么?
难度: 基础
- A. 所有可能使用的索引列表
- B. 表的主键名称
- C. 优化器实际选用的索引
- D. 查询结果必须返回的列名
查看答案与解析
正确答案C
正确原因: key 列是优化器最终选用的索引,key 为 NULL 表示没有使用索引。
关键边界: 候选索引列表在 possible_keys 列,key 可能与 possible_keys 不同,甚至使用覆盖索引。
错误选项辨析: 三个错误选项分别对应 possible_keys、主键信息与列清单,与 key 列的语义不符。
027 慢查询日志中 long_query_time 的作用是?
难度: 基础
- A. 自动杀死执行时间过长的查询
- B. 记录所有 SELECT 语句,无论执行多快
- C. 只记录 INSERT,不记录查询语句
- D. 记录执行时间超过该阈值的 SQL,用于定位低效语句
查看答案与解析
正确答案D
正确原因: 执行时间超过 long_query_time 阈值的语句会写入慢查询日志,是性能分析的主要入口。
关键边界: 默认阈值为 10 秒,日志本身不会终止查询,需要结合 EXPLAIN 分析。
错误选项辨析: 慢日志只记录不杀查询,只记录超阈值的语句,对写语句同样生效。
028 EXPLAIN 中出现 Using filesort 表示什么?
难度: 基础
- A. 在磁盘上创建了临时文件且一定会崩溃
- B. 排序结果随机,无法保证正确性
- C. 排序完全免费,不需要额外内存或磁盘
- D. MySQL 需要额外的排序操作,通常因排序列未匹配索引顺序
查看答案与解析
正确答案D
正确原因: filesort 是额外排序的统称,可能发生在内存或磁盘,常因 ORDER BY 与索引顺序不一致。
关键边界: 让排序列作为索引前缀并按同方向排序,可消除 filesort。
错误选项辨析: filesort 不意味着崩溃或乱序,它也需要额外内存与 CPU,并非免费。
029 关于“深分页问题”,描述正确的是?
难度: 基础
- A. 大 OFFSET 需要扫描并丢弃大量行,页数越深越慢
- B. 页数越深越快,因为需要返回的数据越来越少
- C. OFFSET 只是跳过显示,扫描成本恒为常数
- D. 深分页只影响写入,不影响读取
查看答案与解析
正确答案A
正确原因: 数据库必须先扫描并丢弃 OFFSET 之前的行,OFFSET 越大扫描量线性增长。
关键边界: 延迟关联与基于上一页游标的键集分页可显著改善。
错误选项辨析: 深分页不会变快,扫描成本随 offset 增加,问题主要出现在读取路径。
030 索引条件下推(Index Condition Pushdown)的作用是?
难度: 基础
- A. 把部分 WHERE 条件下推到索引扫描阶段过滤,减少回表行数
- B. 把索引内容复制到应用层由客户端过滤
- C. 关闭索引,强制走全表扫描
- D. 只对主键索引生效,二级索引无效
查看答案与解析
正确答案A
正确原因: 索引条件下推在二级索引扫描时就评估可下推的条件,提前过滤减少回表。
关键边界: ICP 对二级索引尤为有效,引擎不支持时条件会在回表后过滤。
错误选项辨析: ICP 是服务端内部优化,不涉及客户端,不关闭索引,也正适用于二级索引。
031 多个单列索引通过 OR/AND 组合时,优化器可能怎么做?
难度: 进阶
- A. 一定会选择其中一个索引且忽略其他索引
- B. 使用 Index Merge 合并多个索引的扫描结果(type 为 index_merge)
- C. 一定会全表扫描,多索引完全无用
- D. MySQL 不允许一张表存在多个单列索引
查看答案与解析
正确答案B
正确原因: Index Merge 会把多个索引的扫描结果做交、并或排序并集合并,type 显示为 index_merge。
关键边界: Index Merge 并非总是最优,某些组合下优化器仍可能选择全表扫描。
错误选项辨析: 一张表可有多个索引,优化器按成本决策,不会强制只用其中一个。
032 GROUP BY 利用索引顺序避免分组排序的优化称为?
难度: 进阶
- A. 每次分组都必须额外回表读取全行
- B. 松散索引扫描(Loose Index Scan),利用索引有序性直接聚合
- C. GROUP BY 只能使用临时表,与索引无关
- D. 分组查询禁止使用任何索引
查看答案与解析
正确答案B
正确原因: 当分组列符合最左前缀且聚合范围受限时,可沿索引顺序直接聚合,避免 filesort 与临时表。
关键边界: 松散扫描有严格前提(如 MIN/MAX 且每组成员少),不满足时退回紧凑扫描或临时表。
错误选项辨析: 回表、临时表都不是必选,GROUP BY 完全可以走索引。
033 WHERE a = 1 OR a = 2 且 a 上有普通索引时,常见结果是?
难度: 进阶
- A. 一定比等值 AND 查询更快,因为 OR 自动并行
- B. OR 条件下索引一定失效,必须全表扫描
- C. 可能走 Index Merge 或 range 合并,若 OR 混有其他未索引条件则可能全表扫描
- D. 优化器会为 OR 条件自动创建新索引
查看答案与解析
正确答案C
正确原因: 同一列上的 OR 可合并为 range 或 Index Merge;跨列 OR 或含未索引列时风险较大。
关键边界: 可改写为 UNION ALL 等价查询,让每段各自使用索引。
错误选项辨析: OR 不自动并行,也不必然失效,优化器不会自动建索引。
034 设计复合索引时,列顺序的一般原则是?
难度: 进阶
- A. 列顺序任意,只影响命名不影响执行计划
- B. 选择性最低的列必须放在最前面
- C. 把等值条件且选择性高的列尽量放前面,范围条件列尽量靠后
- D. 所有列都必须按表定义时的顺序排列
查看答案与解析
正确答案C
正确原因: 最左前缀决定可用前缀,等值列放前面可让后续列继续参与定位,范围列之后的列通常无法再用于右边界。
关键边界: 实际设计需结合查询模式,没有万能顺序。
错误选项辨析: 列顺序直接影响计划,低选择性列在前会浪费前缀,与表定义顺序无关。
035 索引选择性(基数)的含义与作用是什么?
难度: 进阶
- A. 选择性越低,索引一定越快
- B. 选择性只影响存储大小,不影响执行计划
- C. 选择性等于索引占用的页数
- D. 索引去重值占行数的比例,选择性越高索引越可能被选用
查看答案与解析
正确答案D
正确原因: 优化器依据估计行数决定是否用索引,高选择性索引能显著缩小扫描范围。
关键边界: 低选择性列(如性别)即使建索引,多数查询仍会全表扫描。
错误选项辨析: 选择性低会导致计划差,它与存储大小、页数没有直接等价关系。
036 对 NULL 语义敏感的列,查询 WHERE col <> 1 时通常?
难度: 进阶
- A. 一定比等于查询更快
- B. 不等于查询在 MySQL 中总是报错
- C. 只要列上有索引,不等于必然走索引
- D. 难以有效利用普通索引,因为不等于与 NULL 语义使范围压缩困难
查看答案与解析
正确答案D
正确原因: 不等于与 NULL 语义让优化器难以把范围压缩到很小,通常选择全表扫描或高成本索引扫描。
关键边界: 可改写成等值加 IS NULL 的并集,或按业务调整查询形式。
错误选项辨析: 不等于不会更快,不会报错,索引存在也不保证被使用。
037 线上千万行大表做分页,比较合理的实践是?
难度: 实战
- A. 使用基于上一页最后 id 的键集分页(WHERE id > last_id ORDER BY id LIMIT 20)
- B. 继续用大 OFFSET 分页,让 DBA 定时清理慢查询
- C. 每次查询都 SELECT * 并用随机列排序
- D. 把所有数据一次性加载到应用内存再分页
查看答案与解析
正确答案A
正确原因: 键集分页利用索引直接定位下一页起点,扫描行数恒定,不受页数影响。
关键边界: 键集分页要求排序键稳定且业务支持按游标翻页。
错误选项辨析: 大 OFFSET 扫描量线性增长,SELECT * 带回多余列,全量加载内存不可扩展。
038 某查询 ORDER BY b 走索引后仍出现 Using filesort,最可能的原因是?
难度: 实战
- A. MySQL 的排序算法存在随机缺陷
- B. 索引顺序与排序列不一致,或需要回表取其他列造成额外排序
- C. 表没有主键,必须全表扫描
- D. filesort 表示查询结果会被永久乱序
查看答案与解析
正确答案B
正确原因: 只有当排序列是索引前缀且方向一致时才能免排序,回表取列也可能干扰有序访问。
关键边界: 覆盖索引与按索引顺序声明 ORDER BY 可消除 filesort。
错误选项辨析: filesort 是排序方式描述,结果仍保证正确有序,与表是否缺主键无关。
039 生产代码中避免 SELECT * 的主要原因是?
难度: 基础
- A. SELECT * 会让数据库崩溃
- B. SELECT * 是标准禁止的语法错误
- C. 会带回不需要的列,增加网络与回表开销,也阻碍覆盖索引
- D. SELECT * 会自动创建新索引
查看答案与解析
正确答案C
正确原因: 显式列清单让覆盖索引可行、减少传输字节,并让结果集随表结构变化保持稳定。
关键边界: 需要全部列且查询低频时 SELECT * 也可接受,但不应成为默认。
错误选项辨析: SELECT * 是合法语法,不会崩溃,也不会自动建索引。
040 优化器最终是否选用某个索引,主要依据是?
难度: 进阶
- A. 只要建了索引就一定会被使用
- B. 索引使用与数据分布完全无关
- C. 优化器总是选择 possible_keys 中的第一个
- D. 基于统计信息估计的扫描行数与成本,而不是索引是否存在
查看答案与解析
正确答案D
正确原因: 优化器按统计信息估算成本,选择性差或表很小时宁可全表扫描。
关键边界: 统计信息过期可能导致错误计划,定期 ANALYZE TABLE 有助于修正。
错误选项辨析: 建索引不等于被使用,数据分布是决策核心,possible_keys 顺序不决定选择。