InnoDB支持如下几种索引:html
本文将着重介绍B+树索引。其余两个全文索引和哈希索引只是作简单介绍一笔带过。mysql
哈希索引是自适应的,也就是说这个不能人为干预在一张表生成哈希索引,InnoDB会根据这张表的使用状况来自动生成。sql
全文索引是将存在数据库的整本书的任意内容信息查找出来的技术,InnoDB从1.2.x版本支持。每张表只能有一个全文检索的索引。数据库
B+树索引是传统意义上的索引,B+树索引并不能根据键值找到具体的行数据,B+树索引只能找到行数据锁在的页,而后经过把页读到内存,再在内存中查找到行数据。B+树索引也是最经常使用的最为频繁使用的索引。函数
B+树是一种平衡查找树,其实先想一想看为何要用平衡查找树,不用二叉树?普通的二叉树可能由于插入的数据最后变成一个很长的链表,怎么能提升搜索的速度呢?你能够想一想,为何HashMap和ConcurrentHashMap在JDK8的时候,当链表大于8的时候把链表转成红黑树(红黑树也是平衡查找树)。技术思惟是想通的,那么答案无非是加快速度,性能咯。性能
一个B+树有如下特征:优化
那么咱们先来看一个B+树的图spa
全部的数据都在叶子节点,且每个叶子节点都带有指向下一个节点的指针,造成了一个有序的链表。为何要有序呢?实际上是为了范围查询。好比说select * from Table where id > 1 and id < 100; 当找到1后,只需顺着节点和指针顺序遍历就能够一次性访问到全部数据节点,极大提到了区间查询效率。是否是范围查询的话hash就搞不定这个事情了?如下为B+树的优点:设计
通常性状况,数据库的B+树的高度通常在2~4层,这就是说找到某一键值的行记录最多须要2到4次逻辑IO,至关于0.02到0.04s。指针
汇集索引是按表的主键构造的B+树,叶子节点存放的为整张表的行记录数据,每张表只能有一个汇集索引。优化器更倾向采用汇集索引。由于直接就能获取行数据。
请选择自增id来作主键,不要非空UK列。避免大量分页碎片。下面来看一个汇集索引的图:
那么很简单了,每一个叶子节点,都存有完整的行记录。对于主键的查找速度那是至关的快,美滋滋。
辅助索引也叫非汇集索引,叶子节点除了键值之外还包含了一个bookmark,用来告诉InnoDB在哪里能够找到对应的行数据,InnoDB的辅助索引的bookmark就是相对应行数据的汇集索引键。也就是先获取指向主键索引的主键,而后经过主键索引来找到一个完整的行。若是辅助索引的树和汇集索引的树的高度都是3,若是不是走主键索引走辅助索引的话,那么须要6次逻辑IO访问获得最终的数据页。辅助索引和汇集索引的概念关系图以下:
设计索引的时候,不管是组合索引仍是普通索引等。通常经验是,选择常常被用来过滤记录的字段,高选择性,高区分性。别把性别字段设计索引,性别属于低选择性的。你能够选择名字嘛,你好我大名叫苗嘉杏:)
知道加索引快,可是也别乱加索引,插入以及更新索引的操做InnoDB都会维护B+树的,多加不少索引只会致使效率下降!
不要用重复的索引,好比有个联合索引是a,b,你又整个a列的普通索引。那不是搞事么?
不要在索引上用函数和like
这里咱们先假设B+树高为2,即存在一个根节点和若干个叶子节点,那么这棵B+树的存放总记录数为:根节点指针数*单个叶子节点记录行数。假设一行记录的数据大小为1k,那么单个叶子节点(页)中的记录数=16K/1K=16。
那么如今咱们须要计算出非叶子节点能存放多少指针,咱们假设主键ID为bigint类型,长度为8字节,而指针大小在InnoDB源码中设置为6字节,这样一共14字节,咱们一个页中能存放多少这样的单元,其实就表明有多少指针,即16kb/14b=1170。那么能够算出一棵高度为2的B+树,大概能存放1170*16=18720条这样的数据记录。
根据一样的原理咱们能够算出一个高度为3的B+树大概能够存放:1170*1170*16=21902400行数据。因此在InnoDB中B+树高度通常为1-3层,它就能知足千万级的数据存储。在查找数据时一次页的查找表明一次IO,因此经过主键索引查询一般只须要1-3次逻辑IO操做便可查找到数据。
如何判断一个索引创建的是否好呢?能够用show index from指令查看Cardinality值,这个值是一个预估值,而不是一个准确值。每次对Cardinality值的统计都是随机取8个叶子节点获得的。
对于innodb来讲,达到如下2点就会从新计算cardinality
实际应用中,(Cardinality/行数)应该尽可能接近1。若是很是小则要考虑是否须要此索引。实战一下,好比有一张表,咱们来show index一下
mysql> show index from Order; +---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Order | 0 | PRIMARY | 1 | id | A | 99552 | NULL | NULL | | BTREE | | | | Order | 1 | IDX_orderId | 1 | orderId | A | 96697 | NULL | NULL | | BTREE | | | | Order | 1 | IDX_productId | 1 | productId | A | 52 | NULL | NULL | | BTREE | | | +---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 3 rows in set (0.00 sec)
那么能够看到IDX_productId这个索引的Cardinality比较低。
须要强制刷新Cardinality值的话能够用:
analyze local table xxx;
参考:
MySQL5.1参考手册 - http://dev.mysql.com/doc/refman/5.1/zh/index.html
《MySQL技术内幕》
《小灰漫画》
http://www.javashuo.com/article/p-hwkjuonu-ct.html
http://blog.codinglabs.org/articles/theory-of-mysql-index.html