数据库索引的简单介绍和使用注意事项
树 #
二叉树 #
性质1:在二叉树中第 i 层的结点数最多为2^(i-1)(i ≥ 1)
性质2:高度为k的二叉树其结点总数最多为2^k-1( k ≥ 1)
性质3:对任意的非空二叉树 T ,如果叶结点的个数为 n0,而其度为 2 的结点数为 n2,则:n0 = n2 + 1
二叉搜索树 BST #
若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
左、右子树也分别为二叉排序树;
没有键值相等的节点
平衡二叉树 AVL树 #
平衡二叉树(balanced binary tree),又称 AVL 树。它或者是一棵空树,或者是具有如下性质的二叉树:
它的左子树和右子树都是平衡二叉树,
左子树和右子树的深度之差的绝对值不超过1。
平衡二叉树是对二叉搜索树(又称为二叉排序树)的一种改进。二叉搜索树有一个缺点就是,树的结构是无法预料的,随意性很大,它只与节点的值和插入的顺序有关系,往往得到的是一个不平衡的二叉树。在最坏的情况下,可能得到的是一个单支二叉树,其高度和节点数相同,相当于一个单链表,对其正常的时间复杂度有O(log(n))变成了O(n),从而丧失了二叉排序树的一些应该有的优点。
B树 #
BTree是平衡搜索多叉树,设树的度为2d(d>1),高度为h,那么BTree要满足以下条件:
每个叶子结点的高度一样,等于h;
每个非叶子结点由n-1个key和n个指针point组成,其中d<=n<=2d,key和point相互间隔,结点两端一定是key;
叶子结点指针都为null;
非叶子结点的key都是[key,data]二元组,其中key表示作为索引的键,data为键值所在行的数据;
B+树 #
B+Tree是BTree的一个变种,设d为树的度数,h为树的高度,B+Tree和BTree的不同主要在于:
B+Tree中的非叶子结点不存储数据,只存储键值;
B+Tree的叶子结点没有指针,所有键值都会出现在叶子结点上,且key存储的键值对应data数据的物理地址;
B+Tree的每个非叶子节点由n个键值key和n个指针point组成;
索引 #
聚簇索引和非聚簇索引(也叫:聚集和非聚集) #
MyISAM 非聚簇索引
MyISAM存储引擎采用的是非聚簇索引,非聚簇索引的主索引和辅助索引几乎是一样的,只是主索引不允许重复,不允许空值,他们的叶子结点的key都存储指向键值对应的数据的物理地址。非聚簇索引的数据表和索引表是分开存储的。非聚簇索引中的数据是根据数据的插入顺序保存。因此非聚簇索引更适合单个数据的查询。插入顺序不受键值影响。
InnoDB 聚簇索引
聚簇索引的主索引的叶子结点存储的是键值对应的数据本身,辅助索引的叶子结点存储的是键值对应的数据的主键键值。因此主键的值长度越小越好,类型越简单越好。聚簇索引的数据和主键索引存储在一起。聚簇索引的数据是根据主键的顺序保存。因此适合按主键索引的区间查找,可以有更少的磁盘I/O,加快查询速度。
但是也是因为这个原因,聚簇索引的插入顺序最好按照主键单调的顺序插入,否则会频繁的引起页分裂,严重影响性能。在InnoDB中,如果只需要查找索引的列,就尽量不要加入其它的列,这样会提高查询效率。
索引类型 #
主键索引:根据主键pk_clolum(length)建立索引,不允许重复,不允许空值。
唯一索引:用来建立索引的列的值必须是唯一的,允许空值。
全文索引:文本对象的列构建的索引,倒排索引。
组合索引:用多个列组合构建的索引,这多个列中的值不允许有空值
Hash索引,BTree索引,前缀索引
索引的优点 #
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
- 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
- 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
- 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
- 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
索引优化 #
TODO:
Q&A #
为什么不对每一列都创建索引? #
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
- 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
- 一个表最多16列索引。
应该选择哪些列来创建索引? #
- 在经常需要搜索的列上,可以加快搜索的速度;
- 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
- 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
- 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
- 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
哪些列不应该创建索引? #
- 对于那些在查询中很少使用或者参考的列不应该创建索引。这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。反而由于增加了索引,降低了系统的维护速度和增大了空间需求。
- 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
- 对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
- 当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。