Mysql 索引及优化

什么是索引


索引是什么?相信你们都用过字典。你是怎么从厚厚的新华字典中找到你须要找到的那个字的呢?又是怎么从一本书中快速定位到你须要的章节?
咱们都是经过书中的目录,而后根据目录中的页码定位到咱们要的信息。mysql

一样在mysql中也是这样为咱们准备了一份目录。当你去经过sql语句查询的时候用不用索引,以及怎么用索引。决定了你的查询所耗费的时间。算法

在优化咱们的应用的时候,首先应该考虑的是使用索引,试图经过其它途径来提升性能则纯粹是在浪费时间。你应该先使用索引最大程度的改进性能,再考虑看看是否有其它的技术可使用。sql

因此,索引是什么?—— 是一份通过排序的目录表。数据库

索引的优势


没有索引的数据表:数组

一个没有索引的数据表,就是一个无序的数据行的集合。咱们要从中找到符合条件的一行记录,须要扫描整个表,挨个询问,你是否是?是,留下。不是,找下一个。固然了,经过sql查询出来的数据行也是一个集合。网络

存在索引的数据表:函数

先看一张数据表工具

图片描述

当咱们给Id添加索引的时候生成的索引文件多是这个样子的性能

图片描述

存在索引的数据表,在查询过程当中就不须要再去扫描整张表中的数据行了。好比咱们给Id添加了一个索引,当咱们要查询的条件是:Id=13的时候,咱们开始扫描索引,并找到了3条符合条件的记录行。当扫描到达了Id为14的数据行的时候,这个值高于咱们搜索的值。因为索引是通过分类的,因此当读取到包含14的记录时,咱们就知道再也不会有与Id=13相吻合的数据,从而再也不进行扫描。测试

在上面查询索引文件的时候,使用的是线性扫描,(从第一个,到认为以后不符合条件的最后一个)。另外一种方式是定位算法的使用,它们能够不通过线性扫描就能够直接定位到第一个匹配项。从而节省了大量的搜索时间。各类数据库使用各类各样的技术来迅速的找到索引值。而咱们只须要知道的是索引这个工具用来干啥,怎么用就好了。

在上面的例子中,能够看出不使用索引跟使用索引进行查询时它们的差异。若是还不能给你震撼感,那么举个例子:

假设你有三张没有索引的数据表:t一、t二、t3。每张表有1000条数据行。咱们要找出这三张表中具备相同数值的全部数据行的组合:

SELECT t1.i1,t2.i2,t3.i3
FROM t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.i1 = t2.i2 AND t2.i2 = t3.i3;


这个查询的结果应该有1000个数据行,每行都包含3个相等的数据行。当咱们不使用索引来查询的时候,t1表的每行记录咱们都须要拿到
t2表中进行全表扫描,一样t2表中符合的记录,咱们须要拿到t3表进行全表扫描。
这样子获得符合的记录可能的组合是:1000x1000x1000(10亿)种,比匹配的数目多100万倍。
为数据表编制索引能够很大程度的提升查询的速度,它能够像下面这样处理查询:

1. 从数据表t1中选择第一个数据行,看这个数据行包含什么样的值。
2. 对数据表t2使用索引,直接找到与t1表中相匹配的数据行,相似的对数据表t3使用索引,直接找到与t1表相匹配的数据行
3. 对数据表t1的下一个数据行重复上面的过程,直到检查完t1表中全部的数据行。

使用索引后对t1表仍是进行了全表扫描,可是可以对t二、t3数据表带索引搜寻。直接将那些数据行挑选出来,这种查询运行速度比不带索引的查询运行快100万倍。

Mysql使用索引的方式


  • 在查询操做中把与WHERE子句所给出的条件相匹配的数据行尽快找出来

  • 在关联操做中把与其它数据表里的相匹配的数据行尽快找出来

  • 对于使用MIN()MAX()这些聚合函数,若是数据列带索引,那么它的最小值和最大值可以快速被找到,而不须要进行全表扫描

  • mysql常用索引完成ORDER BYGROUP BY子句的分类和分组操做。

  • 有时候mysql能够经过使用索引避免一个查询扫描完索引文件再去读取数据行。假如你是从MyISam数据表的一个有索引的数据列里选取值,而你并不打算读取其它数据列。在这种状况下Mysql从这个索引文件读取索引值时,你实际上已经获取到了这个值。而这个值你原本是应该经过读取数据行才能获得。在这你就不须要读取两次值了。这也是咱们为何不建议写SELECT * FROM tableName 这种语句。第一,若是仅仅须要获取一个字段值,而且这个值有索引,好比用户的Id主键索引,就不须要查询两次表,直接获取就好了。第二个,对于没必要要的字段,好比文章内容这种占用空间比较大的字段会占用较大的网络带宽。

索引在数据库里的存储方式


对于不一样的存储引擎,索引实现的细节有所不一样。对与MyISAM数据表来讲,数据表的数据行是在数据文件里。而索引值是在索引文件里。一个数据表能够有多个索引,全部的索引都存储在同一个索引文件里。索引文件里的每一个索引都是由分类的关键记录数组组成的。这些数组用于快速访问数据表文件。

InnoDB 存储引擎使用的是一个表空间,在这个表空间里,它管理着全部的InnoDB类型的数据表的数据和索引的存储。咱们也能够经过配置使每一个使用InnoDB引擎的数据表建立本身的一个表空间。

索引的缺点


谈到索引的缺点,仍是回到刚开始咱们介绍什么是索引的时候举的例子。咱们有一本书,书中有目录和内容。当咱们要往这本书里面新增一篇文章的时候步骤是这样的:

  1. 找到这篇文章须要添加的位置,插入进去。

  2. 更新这本书的目录,使读者能够快速的定位到这篇文章。

此时你会发现一个问题,当你新增的文章愈来愈多的时候,你的目录也会变得愈来愈厚。对了~索引会占用必定的磁盘空间。

另外的是,每次新增一篇文章你都得更新下目录。会占用必定的时间。索引也同样,因此当涉及到对有索引的数据表进行插入删除更新,等操做的时候,索引会下降这些操做的性能。之因此会出现这种状况是因为对一条数据行进行插入操做,不只要修改数据表中的数据行,还要求所修改的数据行的索引要作出改变。一个数据表有越多的索引,须要作出的改变就越多,平均性能降低就越多。

绝大多数表都是读操做多过于写操做,但对那些写操做次数比较多的表来讲,索引更新的开销可能会很是大。

  • 对于MyISAM数据表来讲,大量的索引一个数据表有多是索引文件比数据文件更快的达到它的最大尺寸。

  • 存储在InnoDB共享表空间里的所有InnoDB数据表分享一个存储空间。添加索引会使表空间里用于存储的空间更快的减小。和MyISAM数据表不一样的是InnoDB数据表的共享表空间不受操做系统文件尺寸的限制。若是配置成每一个使用InnoDB引擎的数据表使用本身的表空间,数据和索引保存在一个文件里,增长索引将会致使数据表的尺寸更快的逼近文件的最大长度。

尽管有上面所提到的时间和空间上的缺点,可是你见过一本书没有目录吗?因此在使用索引的时候须要均衡的考虑,是否是非用不可。能够多进行几回基准测试,固然了,若是时间容许的话。

挑选索引


尽可能为用来搜索、分类或分组的数据列编制索引

你有一张数据表,该怎么具体为哪个字段添加索引,可以让mysql的优化器找到它,并使用它?

尽可能为用来搜索、分类或分组的数据列编制索引。不要为做为显式或输出的数据列编制索引。也就是说最适合有索引的数据列
是那些在:
    1. 出如今 WHERE 子句中的数据列
    2. 在联结子句中出现的数据列 如:SELECT * FROM aTable INNER JOIN bTable ON aTable.Id = bTable.Id; 
    3. 在 ORDER BY 或 GROUP BY 子句中出现的数据列。

根据 SELECT 子句中出现的数据列仅仅用来输出显式的字段最好不要有索引。

考虑数据列的维度

数据列的维度等于它所容纳的非重复值的个数。好比说有个数据列里面的值分别是:1,5,19,75,5,1。它的维度就是 4 (去掉重复值后)。数据列的维度的最大值等于表里数据行的个数。数据列的维度值越高包含的重复值就越少,索引的使用效果也就越好。

之前在设计表的时候我也纠结过到底要不要给数据表中的 Status(状态)加索引。由于这个字段是常常在WHERE语句中出现的。而实际上这种能够用ENUM数据类型的字段当他在数据表中的数据行出现频率超过30%后mysql的查询优化器一般会跳过索引,而进行全表扫描。如今的优化器更复杂,可以把其它因素考虑进来。百分比再也不是mysql决定进行一次全表扫描而不使用索引的惟一依据了。因此当你认为该数据列的维度确实不是太底的时候能够用DESC或者EXPLAIN与验证下优化器到底有没有使用到索引。

关于复合索引

当你建立了一个n个数据列的复合索引时,实际上就建立了mysql可以使用的n个索引。怎么说呢?好比:

KEY `indexName` (`column1`,`column2`,`column3`);

注意索引的顺序,在查询中可以使用的索引顺序以下:

column1, column2, column3
column1, column2
column1

mysql不能使用没有包含最左边索引字段的索引(column1)。好比:column2,column3。猜测下若是使用column1,column3呢?mysql 能不能用到索引?答案是能够的,但也只用到了column1这个索引,column3这个索引时用不到的。也就是说mysql可以使用到column1去缩小匹配的范围,可是这个索引不能用于这个值的组合。

相关文章
相关标签/搜索