一、索引的优缺点
索引的优点(为什么要有索引)
1、快速取数据
2、保证数据记录的唯一性
3、加快表的连接速度
4、在使用ORDER by、group by子句进行数据检索时,利用索引可以减少排序和分组的时间。
索引的缺点
1、索引需要占物理空间。
2、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。
二、索引的本质
其实, 索引的本质是一个查找问题。索引一般都是用BTree或者BTree的变种(包括B+树、B-树、B*树)
B树(二叉树)
BTree即二叉搜索树。如下图所示。这个的查询应该不用说大家都知道。
如果这个BTree是平衡二叉树,那么他的查询性能是逼近二分查找的。但是如果是下图所示,那么查询的性能会非常差。如何将一棵树转换为平衡二叉树,这个留着以后写。
B-树
是一种多路搜索树(并不是二叉的):
1、定义任意非叶子结点最多只有M个儿子;且M>2;
2、根结点的儿子数为[2, M];
3、除根结点以外的非叶子结点的儿子数为[M/2,M];
4、每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
5、非叶子结点的关键字个数=指向儿子的指针个数-1;
6、非叶子结点的关键字:K[1],K[2], …, K[M-1];且K[i] < K[i+1];
7、非叶子结点的指针:P[1], P[2],…, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
8、所有叶子结点位于同一层;
如:(M=3)的一个B-树如下:
B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点;
B-树有如下特性:
1、关键字集合分布在整颗树中;
2、任何一个关键字出现且只出现在一个结点中;
3、搜索有可能在非叶子结点结束;
B+树
B+树是B-树的变体,也是一种多路搜索树。其定义基本与B-树同,除了以下几点:
1、非叶子结点的子树指针与关键字个数相同;
2、非叶子结点的子树指针P[i],指向关键字值属于[K[i],K[i+1])的子树(B-树是开区间);
3、为所有叶子结点增加一个链指针;
4、所有关键字都在叶子结点出现;
B+树有如下特性:
1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
2.不可能在非叶子结点命中;
3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
4.更适合文件索引系统;
总结如下:
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
该部分参考了http://www.cnblogs.com/oldhorse/archive/2009/11/16/1604009.html
三、索引的分类
按照数据库中可以创建的索引类型来分:
普通索引
这是最基本的索引类型,而且它没有唯一性之类的限制。
创建普通索引的方法如下:CREATE INDEX<索引的名字> ON tablename(列的列表)
唯一索引
不允许其中任何两行具有相同索引值的索引
创建唯一索引的方法如下:CREATEUNIQUE INDEX <索引的名字> ON tablename(列的列表)
主键索引
其实主键索引是唯一索引的一种特殊类型。主键索引支持,在创建表的主键时,主键索引会自动创建。
聚集索引(也叫聚簇索引)
在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。
聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个。
与非聚集索引相比,聚集索引通常提供更快的数据访问速度。
四、索引使用策略及优化
1、小的数据类型通常更好
越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。
2、简单的数据类型更好
整型数据比起字符,处理开销更小,因为字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。
3、尽量避免NULL
应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。
4、如果对多列进行索引(组合索引),列的顺序非常重要
MySQL仅能对索引最左边的前缀进行有效的查找。例如:假设存在组合索引it1c1c2(c1,c2),查询语句select * from t1 where c1=1 and c2=2能够使用该索引。查询语句select *from t1 where c1=1也能够使用该索引。但是,查询语句select * from t1 where c2=2不能够使用该索引,因为没有组合索引的引导列,即,要想使用c2列进行查找,必需出现c1等于某值。