MySQL中如何优化SELECT查询以避免全表扫描?

千萱同学_8015

千萱同学_8015

2026-07-14

938人浏览

原创

type=all代表全表扫描,是必须避免的性能红灯,说明查询未走索引、每次执行都需逐行扫描整表,无论数据量大小都会浪费i/o和cpu资源。

mysql中如何优化select查询以避免全表扫描?

直接说结论:全表扫描不是“慢”,而是“必须避免”的信号——只要 EXPLAIN 显示 type = ALL,就说明这条查询没走索引,哪怕只查10行,也已在浪费I/O和CPU。

为什么EXPLAIN里出现type = ALL就得马上处理

这不是性能“稍差”,而是MySQL被迫读取整张表每一行来过滤。500万行的表,rows = 5000000 意味着每次查询都在磁盘上扫一遍——延迟飙升、连接堆积、从库延迟加剧,都是连锁反应。更隐蔽的问题是:它会挤占Buffer Pool,把其他热数据顶出去,引发更多物理读。

常见诱因包括:

  • WHERE 条件里对索引列用了函数,比如 WHERE YEAR(create_time) = 2023
  • 联合索引只查了右列,比如索引是 (user_id, status),但查询写了 WHERE status = 'paid'
  • 字符串字段没加引号,比如 WHERE user_id = 123(而 user_id 是 VARCHAR)
  • LIKE 以 % 开头,如 WHERE name LIKE '%三'

WHERE 条件怎么写才不丢索引

核心原则:索引列必须单独出现在比较操作符左侧,不能被函数、运算或隐式转换包裹。

  • ❌ 错误:WHERE amount * 1.1 > 100 → 改为 WHERE amount > 90.9
  • ❌ 错误:WHERE DATE(create_time) = '2023-01-01' → 改为 WHERE create_time >= '2023-01-01' AND create_time
  • ❌ 错误:WHERE user_id = 1001(user_id 是 VARCHAR)→ 改为 WHERE user_id = '1001'
  • ❌ 错误:WHERE status != 'cancelled' → 若业务允许,优先用 = 或 IN;否则考虑覆盖索引+强制使用

特别注意:OR 很危险。如果 WHERE a = 1 OR b = 2,且只有 a 有索引,优化器大概率放弃索引走全表扫描。改用 UNION ALL 或拆成两个查询更稳。

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载

索引建在哪?哪些字段值得加

别凭感觉建索引。先看高频查询的 WHERE、JOIN、ORDER BY 字段,再判断选择性(唯一值占比越高越好)。

  • 高价值字段:用户ID、订单号、创建时间、状态码(若状态值离散,如 'pending'/'shipped'/'done')
  • 低价值字段:性别、是否启用(只有 0/1)、地区编码(重复度极高)
  • 联合索引顺序按查询频率排:比如 WHERE user_id = ? AND status = ? ORDER BY create_time DESC,那索引应为 (user_id, status, create_time),不是反过来
  • 单表索引总数控制在 3–5 个以内;每多一个索引,INSERT/UPDATE/DELETE 都要多维护一份B+树

覆盖索引是个强技巧:如果 SELECT id, user_id, status FROM orders WHERE user_id = 123,而你建了 (user_id, status, id) 联合索引,MySQL连主键回表都不用,直接从索引里取完所有字段。

分页查询卡顿,本质还是全表扫描

LIMIT 1000000, 20 看似只取20行,但MySQL必须先跳过前100万行——它得逐行计数,等于扫描了100万零20行。数据量一上千万,秒级延迟就来了。

  • ✅ 替代方案:用游标分页,基于上一页最后一条的 id 或 create_time 做条件,如 WHERE id > 1234567 ORDER BY id LIMIT 20
  • ✅ 大偏移量场景下,可先用子查询定位起始ID:SELECT * FROM orders WHERE id IN (SELECT id FROM orders ORDER BY id LIMIT 1000000, 20)(需确保 id 有索引)
  • ⚠️ SQL_CALC_FOUND_ROWS 已废弃,别再用;总行数应由业务层缓存或异步统计

真正难的不是知道该怎么做,而是每次写完 SELECT 都习惯性跑一遍 EXPLAIN——尤其在WHERE条件加了新字段、JOIN了新表、或者上线前压测时。漏掉一次,可能就是线上接口雪崩的起点。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

4003

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

851

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

1049

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5861

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2783

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5840

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7761

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

1050

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

932

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 178人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 283人学习