第一次写博客,不足之处,多谢指正。

什么是索引

索引是为了加速对表中数据行的检索而创建的一种分散的存储结构。索引是针对表而建立的,它是由数据页面以外的索引页面组成的,每个索引页面中的行都会含有逻辑指针,以便加速检索物理数据

索引的作用

在数据库系统中建立索引主要有以下作用:

  1. 快速取数据;

  2. 保证数据记录的唯一性;

  3. 实现表与表之间的参照完整性;

  4. 在使用ORDER by、group by子句进行数据检索时,利用索引可以减少排序和分组的时间。

索引的优缺点

优点

  1. 大大加快数据的检索速度;

  2. 创建唯一性索引,保证数据库表中每一行数据的唯一性;

  3. 加速表和表之间的连接;

  4. 在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。

缺点

  1. 索引需要占物理空间。

  2. 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。 MySQL索引是在存储引擎中实现的,而不是在服务器层中实现的。所以,每种存储引擎的索引都不一定完全相同,并不是所有的存储引擎都支持所有的索引类型。

MySQL支持的索引类型

  1. B-Tree索引

  2. Hash索引

  3. 全文索引

  4. 空间数据索引(R-Tree)

MySQL支持的存储引擎

  1. MyISAM

  2. InnoDB

  3. MERGE

  4. MEMORY

  5. Archive等。

各存储引擎的比较

Mysql索引相关调研

我们数据库用的存储引擎主要是InnoDB,而InnoDB使用B+Tree进行索引的存储,所以我们主要来研究下InnoDB存储引擎和B+Tree索引。

InnoDB存储引擎

InnoDB优点

InnoDB是一种可靠性高的高性能MySQl数据库存储引擎,主要优点包括:

  1. 它遵循ACID模式设计,具有与事务(Transactions),回滚和保护用户数据的崩溃恢复能力。

  2. InnoDB 提供行级锁(Locking on row level),增加了多用户并发性和性能表现。

  3. InnoDB表基于主键在磁盘上安排数据,优化了常见的查询功能。每一个InnoDB表都有一个叫做聚集索引的主键索引,能尽可能减少数据查询次数。

  4. InnoDB支持外键完整性约束。

  5. 可以与其它MySQL存储引擎混合使用InnoDB表。

  6. InnoDB是针对提高CPU效率而设计的,并且在处理大数据时表现最佳。

InnoDB存储结构

InnoDB存储引擎中的每张表必须得有主键,如果表在创建时没有显示定义主键,则根据以下原则自动创建主键:

  1. 如果有非空的唯一索引,则该索引所在的列为主键;

  2. 如果不符合上述条件,自动创建一个6个字节的指针为主键。

InnoDB存储引擎的逻辑存储结构从大到小分别为:表空间、段、区、页,它们的关系如下图所示:

Mysql索引相关调研

 

InnoDB索引结构

InnoDB使用B+Tree的方式存储索引。为了更好的理解B+Tree索引,我们简单了解下 二叉树、B-树、B+树

二叉树

二叉树即二叉搜索树:

  1. 所有非叶子结点至多拥有两个儿子(Left和Right);

  2. 所有结点存储一个关键字;

  3. 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;

Mysql索引相关调研

 

B-树

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. 所有叶子结点位于同一层。

 

特性

  1. 关键字集合分布在整颗树中;

  2. 任何一个关键字出现且只出现在一个结点中;

  3. 搜索有可能在非叶子结点结束;

  4. 其搜索性能等价于在关键字全集内做一次二分查找;

  5. 自动层次控制。

Mysql索引相关调研

B+树

B+树是B-树的变体,也是一种多路搜索树:

  1. 其定义基本与B-树同,除了:

  2. 非叶子结点的子树指针与关键字个数相同;

  3. 非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);

  4. 为所有叶子结点增加一个链指针;

  5. 所有关键字都在叶子结点出现;

 

特性

  1. 所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;

  2. 不可能在非叶子结点命中;

  3. 非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;

  4. 更适合文件索引系统。

Mysql索引相关调研

B+Tree索引

Innodb的一个表可能包含多个索引,每个索引都使用B+树来存储。索引包括聚集索引和二级索引,聚集索引使用表的主键作为索引键,包含表的所有字段。二级索引只包含索引键和聚集索引键(主键)的内容,不包括其他字段。每一个索引都是一棵B+树,每棵B+树由很多页面组成,而每个页面大小一般为16K。 从B+树的组织结构来看,B树的页面可分为:

  1. 叶子节点:B树层次为0的页面,存储记录的所有内容

  2. 非叶子节点:B树层次大于0的页面,只存储索引键和页面指针。 一棵典型的B+树索引结构如下所示: 从上图可知,相同层次的页面是用一个双向链表连接起来的。一般情况下,从B+树的最左边叶子节点开始,一直向右扫描,就可以得到B+树的从小到大的所有数据。 因此,对于叶子节点,有如下特征:页内数据是按索引键排序的;页面的任一记录的索引键值不小于其左兄弟页面的任何记录。

Mysql索引相关调研

int、timestamp,datetime类型的区别与优劣

int

  1. 占用4个字节

  2. 建立索引之后,查询速度快

  3. 条件范围搜索可以使用使用between

  4. 不能使用mysql提供的时间函数

结论 适合需要进行大量时间范围查询的数据表

timestamp

  1. 占用4个字节

  2. 允许为空值,但是不可以自定义值,所以为空值时没有任何意义。

  3. TIMESTAMP值不能早于1970或晚于2037。这说明一个日期,例如'1968-01-01',虽然对于DATETIME或DATE值是有效的,但对于TIMESTAMP值却无效,如果分配给这样一个对象将被转换为0。

  4. 值以UTC格式保存( it stores the number of milliseconds)

  5. 时区转化 ,存储时对当前的时区进行转换,检索时再转换回当前的时区。

  6. 默认值为CURRENT_TIMESTAMP(),其实也就是当前的系统时间。

  7. 数据库会自动修改其值,所以在插入记录时不需要指定timestamp字段的名称和timestamp字段的值,你只需要在设计表的时候添加一个timestamp字段即可,插入后该字段的值会自动变为当前系统时间。

  8. 以后任何时间修改表中的记录时,对应记录的timestamp值会自动被更新为当前的系统时间。

结论 timestamp类型适合用来记录数据的最后修改时间,因为只要你更改了记录中其他字段的值,timestamp字段的值都会被自动更新。

datetime

  1. 占用8个字节

  2. 允许为空值,可以自定义值,系统不会自动修改其值。

  3. 实际格式储存(Just stores what you have stored and retrieves the same thing which you have stored.)

  4. 与时区无关(It has nothing to deal with the TIMEZONE and Conversion.)

  5. 不可以设定默认值,所以在不允许为空值的情况下,必须手动指定datetime字段的值才可以成功插入数据。

  6. 可以在指定datetime字段的值的时候使用now()变量来自动插入系统的当前时间。

结论 datetime类型适合用来记录数据的原始的创建时间,因为无论你怎么更改记录中其他字段的值,datetime字段的值都不会改变,除非你手动更改它。

MySql索引对NULL的处理

空值与NULL

  1. 空值是不占用空间的

  2. MySQL中的NULL其实是占用空间的

尽量避免NULL: 应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,而且对表索引时不会存储NULL值的,所以如果索引的字段可以为NULL,索引的效率会下降很多。因为它们使得索引、索引的统计信息以及比较运算更加复杂。应该用0、一个特殊的值或者一个空串代替空值。

建立索引的几个原则

  1. 选择唯一性索引;

  2. 为经常需要排序、分组和联合操作的字段建立索引;

  3. 为常作为查询条件的字段建立索引

  4. 尽量使用数据量少的索引

  5. 限制索引的数目;

  6. 尽量选择区分度高的列作为索引[区分度的公式是count(distinct col)/count(*),表示字段不重复的比例];

  7. 尽量的扩展索引,不要新建索引。

使用索引的几个原则

  1. 索引列要保持“干净”,不要进行函数、算术运算或其他表达式运算;

  2. 尽量不用IN、NOT IN、OR 子句,会使索引失效;

  3. 不鼓励使用like操作,如果非使用不可,应like 'aaa%'而不是like '%aaa%',前者可以使用索引;

  4. 如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引;

  5. 最左前缀匹配原则。

参考网址

  1. 高性能MySQL(第3版)

  2. 数据库索引设计与优化

  3. http://blog.csdn.net/hotdust/article/details/51534804

  4. http://www.cnblogs.com/hustcat/archive/2009/10/28/1591648.html

  5. http://www.cnblogs.com/binyue/p/4135121.html

  6. http://tech.meituan.com/mysql-index.html

  7. http://www.ihref.com/read-16422.html

  8. http://blog.csdn.net/zyu67/article/details/46878953

  9. http://www.cnblogs.com/zhiqian-ali/p/5205692.html

  10. http://blog.csdn.net/imzoer/article/details/8518610

相关文章: