资讯专栏INFORMATION COLUMN

mysql innodb 索引使用指南

yedf / 2104人阅读

摘要:索引使用指南索引相关概念聚簇索引使用引擎时,每张表都有一个聚簇索引,比如我们设置的主键就是聚簇索引特点查询数据特别快,因为聚簇索引和行数据存储在磁盘的同一页,这样可以减少磁盘操作次数影响性能的重要因素注意主键索引应该尽量简短二级索引除了聚簇

mysql innodb 索引使用指南

索引相关概念

聚簇索引(clustered index)
使用innodb引擎时,每张表都有一个聚簇索引,比如我们设置的主键就是聚簇索引
特点:查询数据特别快,因为聚簇索引和行数据存储在磁盘的同一页,这样可以减少磁盘I/O操作次数(影响mysql性能的重要因素)
注意:主键索引应该尽量简短

二级索引(secondary index)
除了聚簇索引外的其他索引叫做二级索引(辅助索引),比如我们给除主键外其他字段创建的索引
特点:二级索引里面存储了聚簇索引,最后要通过聚簇索引找到行数据。可见,聚簇索引的效率会影响其他索引

覆盖索引(covering index)
索引包含了查询语句需要的所有数据,这种索引称为覆盖索引
特点:索引的叶子节点中已经包含要查询的数据,不需要回表操作所以很快(减少了磁盘I/O操作次数)

组合索引(multiple-column index)
组合索引也称为复合索引(联合索引),是指把多个字段组合起来创建一个索引(最多16个字段)
特点:遵循最左前缀匹配原则

最左前缀匹配原则(leftmost prefix principle)
mysql会从左向右匹配直到遇到不能使用索引的条件(>、<、!=、not、like模糊查询的%前缀)才停止匹配
设想用a,b,c字段创建一个组合索引(a,b,c)
由于a是索引的最左边前缀,所以where条件中必须匹配字段a,mysql优化器才会用到这个索引
在匹配字段a的前提下,才能匹配字段b
在匹配字段a的前提下,并且匹配字段b,然后才能匹配字段c

使用explain查看执行计划

explain命令用来查看select语句执行计划,确认该SQL语句有没有使用索引,是否做全表扫描,是否使用覆盖索引等

id select_type table type possible_keys key key_len ref rows Extra

type:代表数据访问类型(由左至右,由最差到最好)
| All | index | range | ref | eq_ref | const | system | null |

possible_keys:表示哪些索引可能有利于高效的查找

key:显示mysql决定采用哪个索引来优化查询

key_len:显示mysql在索引里使用的字节数

ref:显示了之前的表在key列记录的索引中查找值所用的列或常量

rows:为了找到所需的行大致需要读取的行数

extra:表示额外的信息(左边较差,右边较好)
| Using filesort| Using temporary | Using where | Using index condition | Using index |
Using index:使用了覆盖索引,速度很快,限于查询字段都位于同一个索引中的场景
Using index condition:表示使用了ICP优化(Index Condition Pushdown),能减少引擎层访问基表的次数和MySQL Server访问存储引擎的次数
Using where:表示在存储引擎检索行后mysql服务器再进行过滤
Using filesort:返回结果前需要做一次外部排序(内存或硬盘),速度慢应该尽量避免
Using temporary:在对查询结果排序时会使用一个临时表,速度慢

创建一张测试表

使用InnoDB引擎创建teacher表,id设为自增主键
mobile、name和birthday建立第一个组合索引idx_one(注意三个字段在索引中顺序)
email、age和name字段建立第二个组合索引idx_two(同样注意顺序)

CREATE TABLE `teacher` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  `birthday` timestamp NULL DEFAULT NULL,
  `email` varchar(32) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `mobile` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_one` (`mobile`,`name`,`birthday`),
  KEY `idx_two` (`email`,`age`,`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
符合最左前缀场景

场景一:mobile是索引的左前缀

explain select * from teacher where mobile = "18600660088";

说明:ref列只出现了一个const,说明使用索引的第一列

场景二:mobile和name加起来是索引的左前缀

explain select * from teacher where mobile = "18600660088" and name = "kevin";

说明:ref列出现了两个const,说明使用索引的前缀mobile和name

场景三:mobile、name和birthday加起来是索引的左前缀

explain select * from teacher where birthday = "2019-01-01" and name = "kevin" and mobile = "18600660088";

说明:ref列出现了三个const,说明使用索引的第一列、第二列和第三列
注意:mysql优化器会自动调整mobile、name、birthday在查询条件中出现的顺序以匹配索引

场景四:只有mobile是前缀,中间跳过了索引中第二列(name),birthday不使用索引

explain select age from teacher where mobile = "18600660088" and birthday = "2019-01-01";

说明:ref列只出现了一个const,说明使用索引的前缀mobile部分

场景五:mobile和name加起来是索引的前缀,并且%位于模糊查询后缀

explain select * from teacher where mobile = "18600660088" and name like "kevin%";

说明:key_len是246与场景二一致,只使用了索引的前缀部分

场景六:mobile和name加起来是索引的前缀,并且%位于模糊查询的前缀

explain select * from teacher where mobile = "18600660088" and name like "%kevin";

说明:mobile字段用到了索引,name不使用索引

场景七:mobile是索引的最左前缀,并且使用了范围查询

explain select * from teacher where mobile > "18600660088" and name = "kevin" and birthday = "2019-01-01";

说明:key_len是51与场景六一致,只使用了索引前缀mobile,name和birthday不使用索引
结论:索引从左往右匹配,遇到范围查询后停止匹配

场景八:name位于组合索引的中间,并且%位于模糊查询后缀

explain select * from teacher where mobile = "18600660088" and name like "kevin%" and birthday = "2019-01-01";

说明:key_len显示251说明跟场景三一致,使用到了整个组合索引
结论:%位于模糊查询后缀不影响索引的使用,如果是组合索引可以继续往右匹配

不使用索引的场景

场景一:缺少前缀mobile字段

explain select * from teacher where name = "kevin chen";

说明:type列显示ALL表示全表扫描,MySQL 从头到尾扫描整张表查找行

场景二:缺少mobile和name组合的前缀字段

explain select * from teacher where birthday = "2019-01-01";

说明:type列显示ALL表示全表扫描,MySQL从头到尾扫描整张表查找行

场景三:like模糊匹配%位于前缀

explain select * from teacher where mobile like "%18600660088";

说明:type列显示ALL表示全表扫描,MySQL从头到尾扫描整张表查找行

场景四:索引列进行了函数运算

explain select * from teacher where trim(mobile) = "18600660088";

说明:正确的做法是在等号的右边做数据运算或函数运算

场景五:字段类型不匹配

explain select * from teacher where mobile = 18600660088;

说明:mobile是varchar类型,18600660088是整数

覆盖索引

场景一:需要的数据都在索引中,走覆盖索引

explain select mobile,name,birthday from teacher where mobile = "18600660088";

说明:Extra列显示附加信息,Using index表示使用覆盖索引

场景二:查询的age字段不在索引中,不能使用覆盖索引

explain select age from teacher where mobile = "18600660088";

使用索引排序

场景一:查询字段和排序字段是同一个索引

explain select id,mobile,name,birthday from teacher order by mobile,name,birthday;

说明:extra显示Using index表示使用了覆盖索引,二级索引中隐含了聚簇索引(主键)

场景二:多个排序字段位于多个不同索引

explain select * from teacher order by mobile, email;

说明:mobil和email属于不同索引,Using filesort说明使用外部排序,不能用索引排序

场景三:多个排序字段不符合最左前缀匹配原则

explain select id,mobile,name,birthday from teacher order by mobile, birthday;

说明:查询用了索引,排序跳过了组合索引中间字段name,extra显示Using filesort

场景四:查询含索引外字段,用索引扫描后再回表查询比直接扫表成本更高,所以没使用索引

explain select * from teacher order by mobile,name,birthday;

说明:extra显示Using filesort表示使用了外部排序

场景五:查询条件字段和排序字段组合起来符合索引最左前缀

explain select * from teacher where mobile="18600660088" order by name;

使用索引分组

场景一:分组字段(多字段组合)属于索引最左前缀

explain select email, age, name from teacher group by email, age, name;

说明:email、age和name组合起来符合最左前缀,使用索引idx_two,extra显示Using index

explain select distinct email, age, name from teacher;

说明:这里distinct字段组合起来同样符合索引最左前缀,使用索引idx_two

场景二:min()/max()函数作用于同一列,并且紧跟属于同一索引的分组字段

explain select email, min(age), max(age) from teacher group by email;

说明:email是分组字段,age是函数作用字段,email和age组合起来符合idx_two最左前缀

场景三:count(distinct)、avg(distinct)和sum(distinct)组合起来符合最左前缀

explain select count(distinct email), sum(distinct age) from teacher;

说明:avg(distinct)和sum(distinct)中distinct只适用单个字段

场景四:count(distinct),distinct适用于多个字段

explain select count(distinct email, age) from teacher;

说明:extra显示Using index for group-by说明使用松散索引扫描(Loose Index Scan)

场景五:缺少组合索引中间部分,不能使用索引排序

explain select email, name from teacher group by email, name;

说明:分组字段缺少idx_two索引age部分,extra显示Using filesort说明使用外部排序

场景六:多个分组字段不属于同一个索引

explain select email, age, birthday from teacher group by email, age, birthday;

说明:birthday不属于idx_two索引,显示Using filesort

场景七:紧凑索引扫描(Tight Index Scan)

explain select email, age, name from teacher where age = 18 group by email, name;

说明:分组字段缺少了完整索引中间部分,但由查询条件 age = 18 补充了这部分常量

场景八:紧凑索引扫描(Tight Index Scan)

explain select email, age, name from teacher where email = "kevin@qq.com" group by age, name;

说明:分组字段不以索引最左前缀开始,但查询条件 email="kevin@qq.com" 提供了这部分常量

参考资料

How MySQL Uses Indexes
Multiple-Column Indexes
ORDER BY Optimization
GROUP BY Optimization
EXPLAIN Output Format

mysql innodb 索引使用指南

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/48473.html

相关文章

  • MySQLInnoDB和MyISAM的存储引擎区别

    摘要:作为,我们应该深刻的认识存储引擎。今天介绍两种最常见的存储引擎和它们的区别和。存储引擎存储引擎不支持事务表锁设计,支持全文索引,主要面向联机分析处理应用,适用于数据仓库等查询频繁的场景。从版本,版本后,两者都支持全文索引。 MySQL数据库区别于其他数据库的很重要的一个特点就是其插件式的表存储引擎,其基于表,而不是数据库。由于每个存储引擎都有其特点,因此我们可以针对每一张表来挑选最合适...

    PingCAP 评论0 收藏0
  • MySQL 内存优化

    摘要:排序区,连接区等缓存是分配给每个数据库会话专用的,其默认值的设置要根据最大连接数合理分配,如果设置过大,不但浪费内存资源,而且在并发连接较高时会导致物理内存耗尽。在一个专用的数据库服务器上,可以将的物理内存分配给。 一、内存优化原则 将尽量多的内存分配给 MySQL 做缓存,但要给操作系统和其他程序的运行预留足够的内存。 myisam 的数据文件读取依赖于操作系统自身的 I/O 缓存...

    zhaofeihao 评论0 收藏0
  • Mysql索引的实现原理

    摘要:下图是索引的原理图这里设表一共有三列,假设我们以为主键,则图是一个表的主索引示意。在中,主索引和辅助索引在结构上没有任何区别,只是主索引要求是唯一的,而辅助索引的可以重复。 Mysql的索引讨论 在MySQL中,索引属于存储引擎级别的概念,不同存储引擎对索引的实现方式是不同的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。 MyISAM索引实现 MyISAM引擎使用...

    Nino 评论0 收藏0
  • 【划重点】MySQL技术内幕:InnoDB存储引擎

    摘要:说明本文绝大部分内容来源技术内幕存储引擎一书,部分图片来源网络。脏页存储于,表示缓冲池中的页与磁盘页不一致,等待被调度刷新。脏页数量太多,比如占据缓冲池比例大于时,强制进行刷新,比例可调。 说明 本文绝大部分内容来源《MySQL技术内幕:InnoDB存储引擎》一书,部分图片来源网络。#我是搬运工# InnoDB 体系结构 后台线程 InnoDB存储引擎是多线程模型,其后台有多个不同的后...

    wuaiqiu 评论0 收藏0
  • MySQLInnoDB存储引擎中count(*)函数的优化

    摘要:聚簇索引和辅助索引聚簇索引每一个存储引擎下的表都有一个特殊的索引用来保存每一行的数据,称为聚簇索引。内部会在含有行值的合成列生成隐藏的聚簇索引。使用这个主键来查找在聚簇索引中的行。 写这篇文章之前已经看过了很多数据库方面的优化内容,大部分都是加索引、使用事务、要什么select什么等等。然而,只是停留在阅读的层面上,很少有实践,因为没有遇到真实的项目,一切都是纸上谈兵。实践是检验真理的...

    adie 评论0 收藏0
  • MySQL 表锁和行锁机制

    摘要:对于和语句,会自动给涉及数据集加排他锁对于普通语句,不会加任何锁当然我们也可以显示的加锁共享锁排他锁和的最大不同点有两个一,支持事务二,默认采用行级锁。排他锁排他锁,也称写锁,独占锁,当前写操作没有完成前,它会阻断其他写锁和读锁。 MySQL 表锁和行锁机制 行锁变表锁,是福还是坑?如果你不清楚MySQL加锁的原理,你会被它整的很惨!不知坑在何方?没事,我来给你们标记几个坑。遇到了可别...

    luckyyulin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<