ITPub博客

首页 > 数据库 > 数据库开发技术 > MySQL全表扫描一定存在性能问题吗?

MySQL全表扫描一定存在性能问题吗?

原创 数据库开发技术 作者:BUAA_dxy 时间:2023-06-25 20:00:00 0 删除 编辑

查找表中的一行数据,数据库有几种实现方法?

答案是两种,全表扫描或者索引查找。

全表扫描就是通过读取整个表中的数据获取查询结果,这种方式最大的问题就是随着数据量的增长,扫描磁盘数据的性能急剧下降。对于 MySQL,我们可以使用 EXPLAIN 命令查看 SQL 语句的执行计划,例如:

示例数据:https://github.com/dongxuyang1985/thinking_in_mysql
EXPLAIN
SELECT *
FROM employee;

Name |Value |
-------------+--------+
id |1 |
select_type |SIMPLE |
table |employee|
partitions | |
type |ALL |
possible_keys| |
key | |
key_len | |
ref | |
rows |25 |
filtered |100.0 |
Extra | |

从以上查询计划的输出结果可以看出,type 字段的值为 ALL,表示使用了全表扫描。

索引查找则是通过索引(通常是 B+树)快速定位数据。以下示例通过主键查找员工信息:

EXPLAIN
SELECT *
FROM employee
WHERE emp_id = 10;

Name |Value |
-------------+--------+
id |1 |
select_type |SIMPLE |
table |employee|
partitions | |
type |const |
possible_keys|PRIMARY |
key |PRIMARY |
key_len |4 |
ref |const |
rows |1 |
filtered |100.0 |
Extra | |

输出中的 type 字段值为 const,表示通过主键或者唯一索引查找数据,并且最多返回一条记录。这是一种非常快速的访问方式,所以相当于一个常量(constant)。

通过索引查找数据时,也可能使用索引范围扫描。例如:

EXPLAIN
SELECT *
FROM employee
WHERE emp_id BETWEEN 10 AND 12;

Name |Value |
-------------+-----------+
id |1 |
select_type |SIMPLE |
table |employee |
partitions | |
type |range |
possible_keys|PRIMARY |
key |PRIMARY |
key_len |4 |
ref | |
rows |3 |
filtered |100.0 |
Extra |Using where|

执行计划输出中的 type 字段值为 range,表示通过主键索引的范围扫描获取数据。

一般而言,通过索引找出数据比全表扫描更加高效,具体分析可以参考这篇文章。

但是仍然存在一些情况下,全表扫描是更好的选择,具体包括:

  • 表中的数据量很小,以至于全表扫描比索引查找更快。尤其是基于辅助索引的范围扫描,因为扫描索引之后还需要回表查询数据,这种查询是随机 IO。例如,数据量少于 10 条的配置表就可以通过全表扫描快速获取数据。

  • 查询语句中没有基于索引字段的过滤条件;或者基于索引的查询条件需要返回表中的一大部分数据,导致全表扫描速度更快。一种应用场景就是数据仓库中的聚合分析,通常需要汇总整个表中的数据。

  • 索引的基数(不同值)太小,例如性别字段的单独索引。这种情况下,MySQL 会认为索引需要查找很多记录,性能不如全表扫描。

执行计划中出现全表扫描,并不一定代表查询存在性能问题,也可能是 MySQL 优化器经过分析之后的正确选择。
如果我们确认全表扫描不是最优方法,可以通过一些技术手段帮助优化器选择其他实现方法,例如使用 ANALYZE TABLE 命令更新统计信息,使用索引提示 FORCE INDEX 强制使用某个索引,或者使用系统变量 max_seeks_for_key 控制索引扫描查找的最大记录数。

原文作者:SQL编程思想;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论
《SQL编程思想》作者,专注于数据库领域知识的分享。

注册时间:2021-08-26

  • 博文量
    443
  • 访问量
    546960