【数据库进阶】为什么你的SQL查询这么慢?索引失效的7个常见场景

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
PolarClaw,2核4GB
简介: 本文总结MySQL索引失效的7大常见场景:模糊查询以%开头、索引列参与计算或函数、隐式类型转换、违背最左前缀法则、OR条件使用不当、不等号查询及全表扫描风险,并结合EXPLAIN工具教你如何诊断与优化,提升查询性能。

前言

在后端开发面试中,“索引失效的场景”是必考题;在生产环境中,它更是导致接口响应缓慢(甚至拖垮数据库)的头号杀手。

很多时候,你明明给字段加了索引,但查询速度依然慢如蜗牛。这时候,你就需要检查一下:你的索引真的生效了吗?

MySQL 的索引就像字典的目录。如果你查找字的方式不对(比如只知道一个字的偏旁,却不知道它的拼音首字母),目录就没用了,只能一页页去翻(全表扫描)。

今天我们盘点7个最容易导致索引失效的“坑”。

准备工作

假设我们有一张用户表 users,并且建立了一个复合索引 idx_name_age (name, age) 和一个单列索引 idx_phone (phone)。

SQL

CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(20),
  age INT,
  phone VARCHAR(20),
  create_time DATETIME,
  KEY idx_name_age (name, age),
  KEY idx_phone (phone)
);

场景一:模糊查询以 % 开头

这是最经典的新手错误。B+树索引是按照顺序排列的,如果你查“以X结尾”的数据,索引无法利用排序特性。

  • 失效写法: LIKE '%刘'LIKE '%刘%'
    SQL
SELECT * FROM users WHERE name LIKE '%刘';
  • 解释:全表扫描。
  • 有效写法: LIKE '刘%'
    SQL
SELECT * FROM users WHERE name LIKE '刘%';
  • 解释:走索引(range),因为知道了开头,利用了“最左前缀”。

场景二:在索引列上做计算

不要在“等号左边”做任何运算,否则数据库需要对每一行数据进行计算后再对比,索引直接作废。

  • 失效写法:
    SQL
SELECT * FROM users WHERE age + 1 = 20;
  • 有效写法:
    SQL
SELECT * FROM users WHERE age = 20 - 1;
  • 原则:把计算交给业务代码或等号右边。

场景三:在索引列上使用函数

同理,使用函数处理索引列也会导致全表扫描。

  • 失效写法:
    SQL
-- 想要查询2023年的用户
SELECT * FROM users WHERE YEAR(create_time) = 2023;
  • 有效写法:
    SQL
SELECT * FROM users WHERE create_time BETWEEN '2023-01-01' AND '2023-12-31';

场景四:隐式类型转换(这个坑最深!)

这是很多资深开发都会栽跟头的地方。 假设 phone 字段在数据库中是 VARCHAR 类型(字符串)。

  • 失效写法:
    SQL
-- 注意:这里的电话号码没有加单引号,是数字类型
SELECT * FROM users WHERE phone = 13800001234;
  • 解释:MySQL 遇到字段类型不匹配(字符串 vs 数字)时,会自动把字符串转成数字进行对比。这就相当于在索引列上使用了隐式函数 CAST(),导致索引失效!
  • 有效写法:
    SQL
-- 加上单引号,保持类型一致
SELECT * FROM users WHERE phone = '13800001234';

场景五:违背“最左前缀法则”

对于复合索引 (name, age),索引的构建是先按 name 排,name 相同再按 age 排。如果你跳过 name 直接查 age,索引就没用了。

  • 失效写法:
    SQL
-- 跳过老大,直接找老二
SELECT * FROM users WHERE age = 18;
  • 有效写法:
    SQL
-- 带上老大
SELECT * FROM users WHERE name = 'Tom' AND age = 18;
-- 或者只查老大
SELECT * FROM users WHERE name = 'Tom';

场景六:使用 OR 条件

如果 OR 两边的条件,只要有一个没有索引,那么整个查询都会变成全表扫描(因为MySQL觉得既然要扫描那部分没索引的数据,不如索性全扫了)。

  • 假设 name 有索引,但在 address 没索引。
  • 失效写法:
    SQL
SELECT * FROM users WHERE name = 'Tom' OR address = 'Beijing';
  • 解决办法:确保 OR 两边的字段都有索引,或者使用 UNION 代替。

场景七:不等号 !=<>

虽然这不是绝对失效(取决于数据量和优化器),但在大多数情况下,查询“不等于”某值的数据,意味着要获取表中“绝大部分”数据,优化器通常会选择全表扫描而不是回表。

  • ⚠️ 风险写法:
    SQL
SELECT * FROM users WHERE name != 'Tom';

如何验证索引是否生效?—— EXPLAIN

别猜,用工具看!在你的 SQL 语句前加上 EXPLAIN 关键字。

SQL

EXPLAIN SELECT * FROM users WHERE name = 'Tom';

重点看 typekey 这两列:

  • key:显示实际使用的索引。如果是 NULL,说明没走索引。
  • type(效率从好到坏):
  • system > const > eq_ref > ref > range > index > ALL
  • 如果 type 是 ALL,说明是全表扫描,必须优化!
  • 如果 type 是 rangeref,说明索引生效了。

总结

索引不是万能药,乱用索引甚至会适得其反。口诀:

全值匹配我最爱,最左前缀要遵守; 带头大哥不能死,中间兄弟不能断; 索引列上少计算,范围之后全失效; 字符引号不能丢,SQL优化有门道。

相关文章
|
4月前
|
SQL 关系型数据库 MySQL
【SQL优化】不再抓瞎!手把手教你读懂MySQL Explain执行计划
本文详解MySQL执行计划工具EXPLAIN,教你读懂其输出的“天书”表格。重点掌握四个核心指标:`type`(访问类型)、`key`(实际使用索引)、`Extra`(额外信息)和`rows`(扫描行数)。通过实战案例解析慢查询成因与优化方案,助你快速定位SQL性能瓶颈,写出高效数据库查询。
|
4月前
|
存储 数据管理 关系型数据库
数据库分库分表
分库分表旨在减轻单库单表压力,提升查询性能。垂直切分按业务或字段拆分,降低耦合、减少IO;水平切分按数据逻辑分布存储,减小单表数据量,实现分布式部署。垂直适用于业务清晰的系统,水平适合单表数据量大场景,各有优劣,需结合实际选择。
|
3月前
|
存储 SQL 关系型数据库
阿里云数据库 RDS(MySQL、SQL Server、PostgreSQL、MariaDB) 收费标准
阿里云数据库RDS(Relational Database Service)是全托管关系型数据库服务,支持MySQL、SQL Server、PostgreSQL和MariaDB四种主流引擎,适配从轻量测试到企业核心业务的不同需求。很多用户会被不同引擎、规格、计费方式的价格差异弄混淆,下面结合最新收费信息,用通俗语言梳理各引擎价格、影响因素及选型建议,帮大家精准把控成本。
587 0
|
3月前
|
人工智能 自然语言处理 Java
Spring AI Alibaba实战:从0到1构建企业级智能应用
本文介绍了基于SpringAI Alibaba框架开发AI原生应用的实战指南。文章首先分析了SpringAI Alibaba作为SpringAI本土化版本的核心优势,包括深度适配阿里云生态、中文语境优化等特性。随后详细讲解了开发环境的搭建过程,包括JDK17、SpringBoot3.2.2等技术栈的配置。通过三个实战案例展示了核心功能实现:基础文本生成、结合MyBatisPlus的智能问答系统、以及流式响应和函数调用等高级特性。
3328 6
|
4月前
|
Nacos 微服务
Nacos与Eureka的区别
Eureka与Nacos均支持服务注册发现、健康监测及集群部署,默认采用AP模式保障高可用。区别在于:Nacos心跳间隔更短(5秒),超时剔除更快,支持配置管理与服务变更广播推送,而Eureka仅提供注册中心功能,更新依赖定时任务。
|
4月前
|
消息中间件 缓存 NoSQL
【Redis进阶】不止是缓存!Redis的5种核心数据结构与实战场景全解析
本文深入浅出地解析了Redis五大核心数据结构:String、Hash、List、Set和ZSet,结合图解与实战场景,涵盖缓存、计数器、分布式锁、购物车、消息队列、排行榜等典型应用,助你摆脱“只会SET/GET”的困境,真正发挥Redis的高性能潜力。
|
4月前
|
JSON NoSQL 关系型数据库
【技术选型】MongoDB vs MySQL:一场没有输家的“双雄对决”
本文深入对比MySQL与MongoDB的核心差异,从理念、性能到实战场景。MySQL严谨规范,适合高一致性业务;MongoDB灵活高效,契合多变需求。通过电商案例解析,揭示两者互补而非替代的关系,帮助开发者按场景选型,实现技术价值最大化。
|
6月前
|
SQL 监控 关系型数据库
mysql 索引失效?怎么解决? (重点知识,建议收藏,读10遍+)
本文总结MySQL索引失效的八大常见场景,如函数操作、类型不匹配、OR连接、违背最左前缀等,并结合实际案例解析。通过EXPLAIN分析执行计划,帮助开发者识别问题,提供优化策略,提升查询性能。