MySQL中的全表扫描和索引树扫描
引言
在学习mysql时,我们经常会使用explain来查看sql查询的索引等优化手段的使用情况。在使用explain时,我们可以观察到,explain的输出有一个很关键的列,它就是type属性,type表示的是扫描方式,代表 MySQL 使用了哪种索引类型,不同的索引类型的查询效率是不一样的。
在type这一列,有如下一些可能的选项:
- system:系统表,少量数据,往往不需要进行磁盘IO
- const:常量连接
- eq_ref:主键索引(primary key)或者非空唯一索引(unique not null)等值扫描
- ref:非主键非唯一索引等值扫描
- range:范围扫描
- index:索引树扫描
- ALL:全表扫描(full table scan)
在上面列出的7种选项中,前面五种我就不详细讲了,可以参考Mysql Explain之type详解这篇文章。我当时对于前五种属性是比较容易就理解了的,但是对于后面两种即索引树扫描和全表扫描我还是存在一些疑问。
索引树扫描我们是比较熟悉的,它就是会遍历聚簇索引树,底层是一颗B+树,叶子节点存储了所有的实际行数据。其实,全表扫描也是扫描的聚簇索引树,因为聚簇索引树的叶子节点中存储的就是实际数据,只要扫描遍历聚簇索引树就可以得到全表的数据了。
那索引树扫描和全表扫描究竟有什么区别呢?
以下将以一个实例来详细分析这两种扫描方式的区别。
实例
我们建立一张t_article表:
create table t_article(
t_article_id int primary key auto_increment,
t_title varchar(40),
);
在我们创建的t_article表中,只有两个字段,一个是主键t_article_id,另一个是普通字段t_title。
我们知道,InnoDB会将聚簇索引默认建立在主键上,而聚簇索引树中的叶子节点就存储了整张表的行数据。
接着,我们分别设计两个sql查询case:
- 走主键索引
explain SELECT t_article_id FROM t_article;
- 走全表扫描:
explain SELECT t_title FROM t_article;
以上两个查询都没有where查询,按理来说底层的sql执行情况应该是差不多的。
结果分析
我们可以来看看上面两种查询的结果,在查询时使用explain语句输出sql执行的详细信息。
- 走索引扫描
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | t_article | index | PRIMARY | 4 | 2 | 100 | Using index |
- 走全表扫描
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | t_article | ALL | 2 | 100 |
从以上两个查询结果中我们可以发现,走主键索引的查询和走全表的查询是不一样的。我们前面也提到了,InnoDB的索引是使用B+树来实现的,而主键索引中存储了整张表的数据,那全表扫描时其实也是扫描的主键索引。那为什么这两种查询会不一样呢?按理来说都是查询的主键索引,它们应该是一样的。
其实,它们两者是有一些细节区别的。
比如,第一个查询,它的优化手段是使用索引树扫描,也就是type中显示的index属性,而且它还使用了覆盖索引,即Extra列中的Using index属性。之所以第一个查询能够使用这两种优化手段,其实是因为select查询的结果列只包含主键,而主键的值是可以直接在遍历聚簇索引树时确定,也不需要回表查询了。
对于第二个查询,它也没有使用where进行过滤,而且它的select结果列包含的是普通列,并不是主键或者其他索引列,所以它会走全表扫描。而全表扫描其实底层也是扫描的聚簇索引树,也就是底层的B+树。这种全表扫描与索引树扫描有一个明显区别,那就是,全表扫描不仅仅需要扫描索引列,还需要扫描每个索引列中指向的实际数据,这里包含了所有的非索引列数据。
前面的分析可能还是有点生硬和难以理解,具体地,我们通过下面一张图来更直观地看一下:

图片源自:从数据页的角度看 B+ 树
从上面的图我们可以看到,对于索引扫描来讲,它只需要读取叶子节点的所有key,也就是索引的键,而不需要读取具体的data行数据;而对于全表扫描来说,它无法仅仅通过读取索引列获得需要的数据,还需要读取具体的data数据才能获取select中指定的非索引列的具体值。所以,全表扫描的效率相比于索引树扫描相对较低一点,但是差距不是很大。
参考
【mysql】全表扫描过程 & 聚簇索引 区别和联系
从数据页的角度看 B+ 树
MySQL中的全表扫描和索引树扫描的更多相关文章
- mysql中的回表查询与索引覆盖
了解一下MySQL中的回表查询与索引覆盖. 回表查询 要说回表查询,先要从InnoDB的索引实现说起.InnoDB有两大类索引,一类是聚集索引(Clustered Index),一类是普通索引(Sec ...
- mysql中如何删除表上的索引?删除索引?
需求描述: 今天在做SQL的优化的时候,想要把mysql中某个表上的索引删除掉,突然忘记语法了,找到帮助,在此记录下 操作过程: 1.查看表上的索引 show index from ti_o_sms; ...
- Mysql如何避免全表扫描的方法
在以下几种条件下,MySQL就会做全表扫描: 1>数据表是在太小了,做一次全表扫描比做索引键的查找来得快多了.当表的记录总数小于10且记录长度比较短时通常这么做. 2>没有合适用于 ON ...
- 点评阿里JAVA手册之MySQL数据库 (建表规约、索引规约、SQL语句、ORM映射)
下载原版阿里JAVA开发手册 [阿里巴巴Java开发手册v1.2.0] 本文主要是对照阿里开发手册,注释自己在工作中运用情况. 本文内容:MySQL数据库 (建表规约.索引规约.SQL语句.ORM映 ...
- mysql中怎样查看和删除唯一索引
mysql中怎样查看和删除唯一索引. 查看唯一索引: show index from mytable;//mytable 是表名 查询结果例如以下: 查询到唯一索引后,怎样删除唯一索引呢,使用例如以下 ...
- MySQL中的联结表
使用联结能够实现用一条SELECT语句检索出存储在多个表中的数据.联结是一种机制,用来在一条SELECT语句中关联表,不是物理实体,其在实际的数据库表中并不存在,DBMS会根据需要建立联结,且会在查询 ...
- Mysql InnoDB 是IOT表 锁基于索引
</pre>Mysql InnoDB 是IOT表 锁基于索引<pre>
- mysql中把一个表的数据批量导入另一个表中
mysql中把一个表的数据批量导入另一个表中 不管是在网站开发还是在应用程序开发中,我们经常会碰到需要将MySQL或MS SQLServer某个表的数据批量导入到另一个表的情况,甚至有时还需要指定 ...
- Mysql怎么样避免全表扫描,sql查询优化
对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引: 尝试下面的技巧以避免优化器错选了表扫描: 使用ANALYZE TABLE tbl_name为扫 ...
随机推荐
- apollo规划控制视频-13 motion planning with autonomous driving
- char的越界赋值即其原理剖析
思考: int ch = 'A'; int ch1 = 65; int ch2 = 321; printf("%c %c %c\n", ch, ch1, ch2);的输出结果是什么 ...
- 印度下架54款中国APP,中东政策逐年收紧,伊拉克成蓝海市场
2月14日,印度电子和信息技术部以"安全威胁"为由对有中国基因的54款App下达禁令,15日,印度税务部门对某些在印中资企业多个场所进行搜查. 本批下架的App中主要以应用类App ...
- 创建axios拦截器
上一篇说axios并发的时候有提到 axios的请求统一管理是为了创建拦截器 具体说一下拦截器的创建 import Vue from 'vue'; import axios from 'axios'; ...
- python-你好
你的程序会读入一个名字,比如John,然后输出"Hello John". 输入格式: 一行文字. 输出格式: 一行文字. 输入样例: Mary Johnson 输出样例: Hell ...
- Python使用函数模拟“汉诺塔”过程
运行效果: 源代码: 1 # -*- coding:utf-8 -*- 2 ##汉诺塔游戏开始 3 _times=0 #用于统计移动次数 4 def hannuota(nlist,mfrom,mpas ...
- pip 和 Conda 镜像站配置
如果你经常使用 Python,那么你对 pip 和 Conda 一定不陌生,它们作为包管理器,可以非常方便的帮助我们下载需要的 Python 包,但是受限于大多 Python 包的服务器在国外,国内下 ...
- js模块系统 - amd|cmd|commonjs|esm|umd
写过前端代码大概率听说过amd cmd umd commonjs esm这些名词, 想当初我第一次看到这些的时候, 人都麻了, 都是些啥啊. 后来我知道了, 这些都是js的模块规范. amd - 浏览 ...
- 动手动脑3&课堂作业(四则运算与继承)
先上结果 Java程序会先把所有的静态模块提取出来优先执行 四则运算主程序代码 1 import java.util.Scanner; 2 3 4 public class main { 5 publ ...
- B. Lord of the Values 思维数学建构 附加 英文翻译
原题链接 Problem - 1523B - Codeforces 题目及部分翻译 While trading on(贸易,利用) his favorite exchange trader Willi ...