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

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

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

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

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+树、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 控制索引扫描查找的最大记录数。

おすすめ

転載: blog.csdn.net/horses/article/details/131228811