MySQL使用索引优化

一、概述

1.1大致目的

  1. 对Mysql存储引擎使用的索引有一个更加深入的理解。
  2. 对Mysql使用索引进行排序来优化查询有个大致了解。
  3. 理解覆盖索引和前缀索引。
  4. 理解联合索引,并能判断选择语句的执行是否使用了索引。

1.2explain关键字

explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。
使用方法,在select语句前加上explain就可以了,本文将大量使用explain关键字,如果不熟悉它结果中的字段信息,可以参考MySQL官方文档:
MySQL官方对explain的使用说明

二、对单列的索引查找

2.1排序方式

mysql可以通过两种方式生成有序的结果:

  1. 通过排序操作
  2. 按照索引顺序扫描数据

由于mysql引擎如默认的Innodb底层使用的是B+树这种索引,所以使用索引扫描来进行排序是很快的。但是想要通过索引扫描的方式来优化排序是有很多限制条件的。

2.2本文建表

我们通过实例来说明什么是联合索引,首先我们先讨论对表单列的索引的情形。

我们使用的测试数据库含两个表,分别叫做:mytest_innodb、mytest_MyISAM,以下为见表语句:

使用InnoDB 创建的表

CREATE TABLE `mytest_innodb` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `country` varchar(255) NOT NULL,
  `address` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `height`int(11) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

使用MyISAM存储引擎创建的表

CREATE TABLE `mytest_myisam` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `country` varchar(255) NOT NULL,
  `address` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `height`int(11) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM;

我们对两个表填入相同的数据,保证两表除了引擎不同外,其他的表结构、表的内容全部一致,表的内容,结构如下:
下图为两个表的结构:
《MySQL使用索引优化》
下图为两张表的信息(一样):
《MySQL使用索引优化》
我们在建立两个没有主键的表,即分别对上面见表语句将 PRIMARY KEY (id)去掉,名字命名为no_prikey_inno和no_prikey_mysi。
我们从表的结构知道,我们未设置其他索引。事实上,此时数据库表文件中会存储这关于主键的B+树索引,我们有如下测试:

2.3Innodb下的分析

我们先对Innodb引擎进行分析:
《MySQL使用索引优化》
由于Innodb引擎是聚集引擎,它的索引和数据是存储在一起的,对于该表若有主键,则底层IBD文件中必定存放着关于主键的B+树索引,并且该课B+树的叶子节点会存放对应主键所对应的所有字段信息。
根据以上信息我们分析上述查询结果:
①在Innodb引擎下,对没有主键的表不管用什么方式(创建表后不再添加索引的情况下)查询,查询方式均不会使用索引。
②在Innodb引擎下,对于有主键的表(创建表后不再添加索引的情况下),若是where查询,限制条件是关于主键的则会走索引,在where条件下限制条件不是主键,则查询用到索引。当我们使用Oreder by进行对主键的升降序后必定走索引,此时在用where限制任何字段均不影响,索引的使用,这是因为对于底层B+树来说,我们只要通过主键排序后(这会使用索引),就可以轻松查询带其他字段(叶子节点下面挂着所有字段)

2.3MyISAM下的分析

我们在对MyISAM引擎进行分析:
《MySQL使用索引优化》
可以看到,在使用MyiSAM下,对于不适用主键的情况是和Innodb一致的,但是使用主键的情况下,MyiSAM只对id的查找有用索引。这是为什么呢?
这是由于MyiSAM是非聚集引擎,它将数据和索引分开存储了,这样对于在建完表后不加索引下,它的索引文件只存放索引,所以若查询索引之外的东西,必然会跨文件查找,会产生IO。

2.4底层文件分析

由于mysql是关系型数据库,这意味着数据的存储是在磁盘上的,所以我们有必要对其底层文件进行一定分析:
《MySQL使用索引优化》
可以看出对于MyiSAM文件在有无主键下MYI文件会差了1KB这是因为该文件是存放索引的,在无主键下,该文件下就无索引,必定会比有索引的主键下的存储容量少。
而Innodb的ibd文件却看不出有无主键下存储容量的差别,这是由于该文件中还存放数据,对于大容量的数据字段,索引的大小真的是微不足道,这也使得使用索引的查询会更高效,速度会更快。

三、联合索引

3.1 建立主键外的索引

我们在上面已经讨论过单个基于主键的索引,还有一种单个索引是表中没有索引,我们建立一个索引,这个索引可以不是主键,这种情况和单个主键索引类似,在此不在说明了。
所以现在,我们开始讨论对多个字段建立索引,先考虑非联合索引下的多个索引。下面我们改变上述见表语句,通过ALTER语句增加索引。详细见下:

 alter table mytest_innodb add key (age);
 alter table mytest_myisam add key (age);

新的两张表结构如下:
《MySQL使用索引优化》

我们测试:
《MySQL使用索引优化》

这里我们发现对于age的索引查找若是查找自己本身的字段或者index是使用索引的,但查找包含其他字段时就不会使用索引。
这是因为,对于其他的非主键添加索引,它形成的B+树索引的叶子节点里面只会存储索引(该索引字段本身作为B+树的索引)。
所以在我们使用age排序后的全部字段的查找是要进行Using filesoret的。
但是注意一个很重要的一点就是 age的B+树是如何和主键的这一棵“主B+树”联系到一起的呢?
《MySQL使用索引优化》
如上图,注意上图和上上图第一个例子的区别:
在通过age排序后对于一个确定值的所有有关字段的查找是这样子的,先通过age这棵B+树寻找到要查询位置的age,并且这个叶子节点是存放着主键的索引,于是MySQL会通过该索引到“主B+树”上查找到该主键对应的所有信息。

对于MyISAM我们考虑下图的这种情况,
《MySQL使用索引优化》
这是因为MyiSAM是索引和数据分开的且,age索引下并未存放id主键而是存放的是存放数据的地址。(myisam数据存在地址里,索引下面直接存地址,这也是为什么它的查早速度快的其中一个原因)

3.2联合索引的基本概念

首先,联合索引是指对表上的多个列进行索引。但这多个列的索引是有限制,有关联的,满足“最左原则”。
联合索引的创建方法与单个索引创建的方法一样,不同之处仅在于有多个索引列。

联合索引的内部结构
我们以 KEY idx_age_height为例子看下联合索引内部B+树的结构:
《MySQL使用索引优化》
从本质上来说,联合索引也是一颗B+树,不同的是联合索引的键值的数量不是1,而是大于等于2,这取决于要联合的字段个数。我们如上图建立的联合索引是关于age和height的,键值是按照顺序排列的,这里我们不得不提到“最左原则”。

最左原则
在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配,并且底层B+树的排序也是先从最左边开始依次往右按照优先级进行排序。

联合索引产生的若干个索引
联合索引的最左原则就是建立索引KEY union_index (a,b,c)时,等于建立了(a)、(a,b)、(a,b,c)三个索引,从形式上看就是索引向左侧聚集,所以叫做最左原则,因此最常用的条件应该放到联合索引的组左侧。

四、联合索引下的查询分析

前缀索引

覆盖索引

《MySQL使用索引优化》

未写完

    原文作者:徐志
    原文地址: https://segmentfault.com/a/1190000020040290
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞