MySQL数据库索引(中)

上一篇回顾:数据库

1.一个索引对应一颗B+树,全部的真实记录都是存在叶子节点里面的,全部的项目录都存在内节点或者说根节点上。性能

2.innodb会为咱们的表格主键添加一个聚簇索引,若是没有主键的话数据库是会为咱们自动添加row_id这一列的。聚簇索引的叶子节点包含完整的用户记录。spa

3.咱们是能够为本身感兴趣的列添加二级索引的,二级索引的叶子节点没有用户完整的信息,只是拥有对应列和主键的信息,若是想要拥有完整的信息是须要进行回表操做用二级索引找到的主键去聚簇索引寻找完整信息。3d

4.B+树的每一层节点都是按照索引列的大小信息进行排序而组成的双向链表,每一个页里里面的记录也是按照索引列大小信息组成的单向链表。若是是联合索引的话,先按照前面的列进行排序,若是是相同的状况下再根据其余的列进行排序。code

5.每一个索引的搜索都是从根节点进行的,因为每一个页面都按照索引列的值创建了Page Directory,因此在肯定了具体页面信息的状况下是能够根据二分法进行快速的定位的。blog

索引的代价:排序

1.空间上的代价:每个索引对应的都是一颗B+树,B+树的每个节点都对应的是一个16kb大小的数据页,若是是一个很大的数据库的话那么占用的内存仍是很大的。索引

2.时间上的代价:咱们在上面讲过,每层节点都是按照数据的大小顺序进行排列的单向链表,每一个页也是按照大小排列的双向链表。那么咱们在对数据进行操做的时候必然避免不了的就是数据的迁移,数据页的删除,回收,分裂等等,若是咱们建立的索引过多的话那么对应的问题就是频繁的须要对这些东西进行操做。那就是浪费时间,给性能拖后腿。内存

B+树适用的范围:字符串

1:建立一个咱们这篇文章须要用到的数据表:

咱们建立好表格之后须要注意的问题:

1>咱们是没有主键的,那么是由数据库给咱们生成主键,而后再根据主键建立聚簇索引;

2>咱们本身建立的索引是没有包含country这个列的,因此咱们索引的叶子节点只包含name,birthday,phon_num的值以及数据库帮助咱们建立的主键row_id;

下面咱们给出的就是这个索引的示意图:咱们用颜色对内节点以及叶子节点进行了区分,并且咱们必需要注意的就是这是根据name先排序,而后再根据birthday、phon

 

全值匹配:

若是是咱们进行查询的数据列和咱们索引全部列的顺序都是同样的话,那么咱们称之为全值匹配,以下所示的查询:

咱们就能够利用索引进行快速的肯定name=asiz的位置,而后若是有相同数据的话再根据这个信息进行birthday和phon_num的匹配。由于咱们的索引是现根据name进行排序,再根据birthday和phon_num进行的排序。

可是,若是咱们要是改变了这个顺序,首先使用birthday进行查询的话,那么就是不能使用这个索引,只能全文检索了。由于咱们的索引都是先根据name进行排序的。

因此咱们在使用联合索引的时候必需要严格按照顺序,至于里面具体的规则咱们下面在讲。

匹配最左边的列:

1>只包含最左边的一个列:以下图所示,这样也是可使用到咱们的联合索引的

2>包含左边的多个列:以下图所示,这样操做也是没问题的

3>若是咱们在查询的时候没有使用到最左边的name列,以下图所示,这是不能使用索引的,只能进行全文的检索

注意:

  因此咱们在使用联合索引的时候,务必须要记住的就是必定要使用到第一个列,由于咱们的索引就是按照第一个列最早开始排序的,若是不按照这个规则进行,那么咱们是不能使用到索引的。并且,就如咱们最后一条查询而言,咱们在进行完成name的索引之后,在相同状况下进行phon_num的查询的时候是不能使用索引的,由于name完成之后是根据birthday进行的索引排序,因此必定要严格按照索引定义的顺序进行查找。

匹配值前缀:

1>若是咱们在进行字符串的搜素的时候是没有必要输入完整的字符串的,就好像咱们的模糊查询,咱们只须要输入字符串的前面字母便可获得筛选的结果,由于B+树是现根据name进行排序的,咱们只使用前面的部分字符也是能够进行二分查找迅速定位。

2>若是咱们给定的字符是位于字符串中间,那么这样是不可行的,是不能使用索引的,只能进行全文的检索,以下图所示:

范围匹配:

1>咱们的索引也是能够应用在范围查询里面的,以下图所示,由于咱们的数据都是在页内按照单向链表进行排列,页之间是按照双向链表进行排列,因此是能够很快速获取到咱们须要的数据:

2>可是咱们在使用多个列的范围查找的时候咱们只能使用到的是第一列的索引,可是其余列的索引咱们是使用不到的,由于咱们是根据查询出来的结果在不一样的name里面在进行birthday的筛选,索引是根据相同name的条件下才对birthday进行排序的,以下图所示:

精确匹配某一列并范围匹配某一列:

对于同一个索引来讲,咱们使用多个列的范围查询的时候,只能使用最左边列的B+树,其余列是不能使用的。可是咱们左边使用的是精确查询,右边使用的是范围查询,那么,咱们的右边也是可使用到B+树的,以下图所示:

咱们分析一下上图:

  1>第一部分的name进行的精确匹配固然是可使用到索引的

  2>由于咱们name是同样的,和索引的排序规则一致,因此birthday的范围搜索也是可使用到B+树的

  3>由于birthday的范围进行不一样查找的结果,因此咱们在进行phon_num的查找的时候是不能使用B+树的。

用于排序:

 咱们在使用排序好比说Order by的时候也是可使用到索引的,以下图所示,具体的规则和咱们进行查询的时候是同样的,由于咱们索引就是按照顺序已经进行好排序的,因此若是咱们的排序的顺序和索引的顺序是一致的,那么彻底没问题能够直接取用数据,可是就是一直强调的问题,若是咱们列的顺序改变了们就不能在使用B+树了。

用于分组:

 以下所示,咱们在使用group by的时候须要进行分组,这个过程包含了三个部分,第一个是先对name一致的进行分组,第二个在着基础上在对birthday一致的进行分组,而后最后在基础上对phon_num一致的进行分组。这就正好和咱们的索引是一致的,因此是可使用到B+树的,和上面同样,咱们的顺序问题是坚定的不能乱的。

索引的挑选:

1>必须条件:只为咱们使用到的查询条件,分组,排序列建立索引。查询列表里面的列咱们没有必要创建索引。

2>基数考虑:若是一个列的差别数据不是不少,咱们称之为基数小的列。也就是说全部数据的这个列的数据大部分都相同,那么就是基数小,这种列不必建立索引。

3>数据类型:咱们知道的是索引列能够有不少的数据类型,好比说整形数据咱们就有TINYINTMEDIUMINTINTBIGINT,它们所占用的空间内存确定是不同的,因此咱们挑选数据类型小的类型做为索引列的数据类型,能够有效的节约空间,储存更多的数据,那么咱们在进行数据取用的时候一次能够加载更多的数据进入内存,减少IO损耗,同时在CPU层次来讲,数据类型越小,查询处理的速度是越快的。

4>索引字符串的前缀:这个问题咱们在上面其实提到过,咱们在使用索引的时候是能够的,那么在建立索引的时候固然也是能够的,这样能够减小不少的内存空间,e并且咱们在作字符串比较的时候若是咱们使用的是前缀那么比较的时间也是能够大大进行缩短的。具体的语法以下:

5>尽可能使用联合索引:由于咱们的每个索引对应的都是一颗B+树,须要使用时间和空间进行维护的,咱们文章开始就说了索引须要付出的代价。咱们使用联合索引,是能够知足不少字段的索引条件的。

6>主键插入的顺序:记不记得咱们在上边说的,索引的一个目录项对应的是一个页,咱们的数据都是有序的进行单向链表的维护,那么若是咱们的主键在后期插入中间的话就涉及到了位置的移动,目录项的修改,页面分裂,数据迁移等等问题。因此咱们建议的是让数据库给主键进行自增生成。

7>避免冗余重复的索引:不要为一个列重复的添加多个索引,这样是很差的,他对效率的提高没有半点的帮助,可是对空间的消耗确实实打实的。

8>覆盖索引:好比咱们开始建立的索引是没有包含country这个列的,若是咱们以下图所示进行查询,咱们原本是能够在索引直接获得三个列的数据,可是差一个列,这时候就必须用主键去聚簇索引进行回表操做了。因此咱们查询的列最好都是咱们索引的列,也就是说咱们是鼓励把须要查询的列明确进行书写的。

相关文章
相关标签/搜索