索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。html
根据数据库的功能,能够在数据库设计器中建立三种索引:惟一索引、主键索引和汇集索引。node
性质:B+树是B-树的变体,也是一种多路搜索树:mysql
1.其定义基本与B-树同,除了:算法
2.非叶子结点的子树指针与关键字个数相同;sql
3.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);数据库
4.为全部叶子结点增长一个链指针;数据库设计
5.全部关键字都在叶子结点出现;函数
B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树能够在oop
非叶子结点命中),其性能也等价于在关键字全集作一次二分查找;源码分析
B+的特性:
1.全部关键字都出如今叶子结点的链表中(稠密索引),且链表中的关键字刚好是有序的;
2.不可能在非叶子结点命中;
3.非叶子结点至关因而叶子结点的索引(稀疏索引),叶子结点至关因而存储(关键字)数据的数据层;
4.更适合文件索引系统;
B-/+Tree索引的性能分析
通常使用磁盘I/O次数评价索引结构的优劣。先从B-Tree分析,根据B-Tree的定义,可知检索一次最多须要访问h个节点。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每一个节点只须要一次I/O就能够彻底载入。为了达到这个目的,在实际实现B-Tree还须要使用以下技巧:
每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。
B-Tree中一次检索最多须要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)。通常实际应用中,出度d是很是大的数字,一般超过100( B+ trees have very high fanout (number of pointers to child nodes in a node, typically on the order of 100 or more)),所以h很是小(一般不超过3)。
综上所述,用B-Tree做为索引结构效率是很是高的。
而红黑树这种结构,h明显要深的多。因为逻辑上很近的节点(父子)物理上可能很远,没法利用局部性,因此红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差不少。
上文还说过,B+Tree更适合外存索引,缘由和内节点出度d(>节点的度:一个节点含有的子树的个数称为该节点的度;>树的度:一棵树中,最大的节点的度称为树的度)有关。从上面分析能够看到,d越大索引的性能越好,而出度的上限取决于节点内key和data的大小:
dmax = floor(pagesize / (keysize + datasize + pointsize))
floor表示向下取整。因为B+Tree内节点去掉了data域,所以能够拥有更大的出度,拥有更好的性能。
下图是一个简单的B+Tree示意。
MySQL索引实现
在MySQL中,索引属于存储引擎级别的概念,不一样存储引擎对索引的实现方式是不一样的,本文主要讨论MyISAM和InnoDB两个存储引擎的索引实现方式。
走进搜索引擎的做者梁斌老师针对B树、B+树给出了他的意见(为了真实性,特引用其原话,未做任何改动): “B+树还有一个最大的好处,方便扫库,B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持range-query很是方便,而B树不支持。这是数据库选用B+树的最主要缘由。
好比要查 5-10之间的,B+树一把到5这个标记,再一把到10,而后串起来就好了,B树就很是麻烦。B树的好处,就是成功查询特别有利,由于树的高度整体要比B+树矮。不成功的状况下,B树也比B+树稍稍占一点点便宜。
B树好比你的例子中查,17的话,一把就获得结果了,
有不少基于频率的搜索是选用B树,越频繁query的结点越往根上走,前提是须要对query作统计,并且要对key作一些变化。
另外B树也好B+树也好,根或者上面几层由于被反复query,因此这几块基本都在内存中,不会出现读磁盘IO,通常已启动的时候,就会主动换入内存。"
MyISAM索引实现(http://blog.codinglabs.org/articles/theory-of-mysql-index.html)
MyISAM引擎使用B+Tree做为索引结构,叶节点的data域存放的是数据记录的地址。下图是MyISAM索引的原理图:
这里设表一共有三列,假设咱们以Col1为主键,上图是一个MyISAM表的主索引(Primary key)示意。能够看出MyISAM的索引文件仅仅保存数据记录的地址(默认是以存储顺序)。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是惟一的,而辅助索引的key能够重复。若是咱们在Col2上创建一个辅助索引,则此索引的结构以下图所示:
一样也是一颗B+Tree,data域保存数据记录的地址。所以,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,则取出其data域的值,而后以data域的值为地址,读取相应数据记录。
MyISAM的索引方式也叫作“非汇集”的,之因此这么称呼是为了与InnoDB的汇集索引区分。
InnoDB索引实现
虽然InnoDB也使用B+Tree做为索引结构,但具体实现方式却与MyISAM大相径庭。
第一个重大区别是InnoDB的数据文件自己就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件自己就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,所以InnoDB表数据文件自己就是主索引。
上图是InnoDB主索引(同时也是数据文件)的示意图,能够看到叶节点包含了完整的数据记录。这种索引叫作汇集索引。由于InnoDB的数据文件自己要按主键汇集,因此InnoDB要求表必须有主键(MyISAM能够没有),若是没有显式指定,则MySQL系统会自动选择一个能够惟一标识数据记录的列做为主键,若是不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段做为主键,这个字段长度为6个字节,类型为长整形。
第二个与MyISAM索引的不一样是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的全部辅助索引都引用主键做为data域。例如,上图为定义在Col3上的一个辅助索引:
这里以英文字符的ASCII码做为比较准则。汇集索引这种实现方式使得按主键的搜索十分高效,可是辅助索引搜索须要检索两遍索引:首先检索辅助索引得到主键,而后用主键到主索引中检索得到记录。
了解不一样存储引擎的索引实现方式对于正确使用和优化索引都很是有帮助,例如知道了InnoDB的索引实现后,就很容易明白为何不建议使用过长的字段做为主键,由于全部辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段做为主键在InnoDB中不是个好主意,由于InnoDB数据文件自己是一颗B+Tree,非单调的主键会形成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段做为主键则是一个很好的选择。
使用explain对sql进行优化:
1) consts 单表中最多只有一个匹配行(主键或者惟一索引),在优化阶段便可读取到数据。
2) ref 指的是使用普通的索引。(normal index)
3) range 对索引进范围检索。
反例:explain 表的结果,type=index,索引物理文件全扫描,速度很是慢,这个 index 级别
比较 range 还低,与全表扫描是小巫见大巫。
当使用索引时,InnoDB会锁住它不须要的元组。更糟糕的是,若是查询不能使用索引,MySQL会进行全表扫描,并锁住每个元组,不论是否真正须要
Hash索引
MySQL中,只有Memory存储引擎显示支持hash索引,是Memory表的默认索引类型,尽管Memory表也可使用B-Tree索引。
CREATE TABLE lookup
(id INT, INDEX USING HASH (id))
ENGINE = MEMORY;
CREATE TABLE lookup
(id INT, INDEX USING BTREE (id))
ENGINE = MEMORY;
Memory存储引擎支持非惟一hash索引,这在数据库领域是罕见的,若是多个值有相同的hash code,索引把它们的行指针用链表保存到同一个hash表项中。
假设建立以下一个表:
CREATE TABLE testhash (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
KEY USING HASH(fname)
) ENGINE=MEMORY;
包含的数据以下:
假设索引使用hash函数f( ),以下:
f('Arjen') = 2323 f('Baron') = 7437 f('Peter') = 8784 f('Vadim') = 2458 |
此时,索引的结构大概以下:
Slots是有序的,可是记录不是有序的。当你执行
mysql> SELECT lname FROM testhash WHERE fname='Peter';
MySQL会计算’Peter’的hash值,而后经过它来查询索引的行指针。由于f('Peter') = 8784,MySQL会在索引中查找8784,获得指向记录3的指针。
由于索引本身仅仅存储很短的值,因此,索引很是紧凑。Hash值不取决于列的数据类型,一个TINYINT列的索引与一个长字符串列的索引可能同样大。
Hash索引有如下一些限制:
(1)因为索引仅包含hash code和记录指针,因此,MySQL不能经过使用索引避免读取记录。可是访问内存中的记录是很是迅速的,不会对性能形成太大的影响。
(2)不能使用hash索引排序。
(3)Hash索引不支持键的部分匹配,由于是经过整个索引值来计算hash值的。
(4)Hash索引只支持等值比较,例如使用=,IN( )和<=>。对于WHERE price>100并不能加速查询。
mysql Btree与hash索引的区别(https://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html)
位图索引是一种针对多个字段的简单查询设计一种特殊的索引,适用范围比较小,只适用于字段值固定而且值的种类不多的状况,好比性别,只能有男和女,或者级别,状态等等,而且只有在同时对多个这样的字段查询时才能体现出位图的优点。
位图的基本思想就是对每个条件都用0或者1来表示,若有5条记录,性别分别是男,女,男,男,女,那么若是使用位图索引就会创建两个位图,对应男的10110和对应女的01001,这样作有什么好处呢,就是若是同时对多个这种类型的字段进行and或or查询时,可使用按位与和按位或来直接获得结果了。