数据库索引

索引是存储引擎用于快速找到记录的一种数据结构。

索引目的

索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql

索引原理

索引类别

  • 大多数索引指的是B-树索引,InnoDB索引使用的数据结构是B+Tree

  • MySQL中的MEMORY存储引擎显示支持哈希索引,哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效,存储引擎会对所有的索引列计算一个哈希码,哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。如果哈希值发生冲突,哈希索引会以链表的方式存储多个记录指针到同一个哈希条目中

  • 空间数据索引:MyISAM存储引擎支持,无需前缀查询,会从所有维度来索引数据。

磁盘I/O与预读

磁盘读取数据靠的是机械运动,每次读取数据花费的时间可以分为寻道时间、旋转延迟、传输时间三个部分:

  • 寻道时间指的是磁臂移动到指定磁道所需要的时间,主流磁盘一般在5ms以下;
  • 旋转延迟就是我们经常听说的磁盘转速,比如一个磁盘7200转,表示每分钟能转7200次,也就是说1秒钟能转120次,旋转延迟就是1/120/2 = 4.17ms;
  • 传输时间指的是从磁盘读出或将数据写入磁盘的时间,一般在零点几毫秒,相对于前两个时间可以忽略不计。

那么访问一次磁盘的时间,即一次磁盘IO的时间约等于5+4.17 = 9ms左右,听起来还挺不错的,但要知道一台500 -MIPS的机器每秒可以执行5亿条指令,因为指令依靠的是电的性质,换句话说执行一次IO的时间可以执行40万条指令,数据库动辄十万百万乃至千万级数据,每次9毫秒的时间,显然是个灾难。

考虑到磁盘IO是非常高昂的操作,计算机操作系统做了一些优化,当一次IO时,不光把当前磁盘地址的数据,而是把相邻的数据也都读取到内存缓冲区内,因为局部预读性原理告诉我们,当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。每一次IO读取的数据我们称之为一页(page),也就是读取一页内的数据时候,实际上才发生了一次IO

B+树索引

B+树是B树的一种变种,B树是一个节点可以拥有超过2个子节点的二叉查找树。

如上图所示,浅蓝色是磁盘块,深蓝色代表数据项,黄色代表指针

叶子节点存储真实的数据,非叶子节点只存储指引方向的数据项。如磁盘块1包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。

查找过程:

如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO;

在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO;

29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO;

真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

索引的优点

  1. 索引大大减少了服务器需要扫描的数据量
  2. 帮助服务器避免排序和临时表
  3. 可以将随机I/O变为顺序I/O

创建索引

唯一的索引 (Unique Index):在表格上面创建某个一个唯一的索引。唯一的索引意味着两个行不能拥有相同的索引值。

CREATE UNIQUE INDEX 索引名称 ON 表名称 (列名称) 

列名称规定需要索引的列

简单索引:省略UNIQUE值,这样就可以使用重复的值

实例:

CREATE INDEX PersonIndex ON Person (LastName)

//索引不止一列时,使用逗号隔开列名
CREATE INDEX PersonIndex ON Person (LastName, FirstName)

参考:

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

http://blog.jobbole.com/24006/


索引分类:

普通索引:创建普通索引时,没有任何限制条件

唯一性索引:使用UNIQUE关键字创建,主键就是一种特殊的唯一性索引

全文索引:FULLTEXT,只能创建在CHAR、VARCHAR或TEXT类型的字段上。只有MyISAM存储引擎支持全文检索

单列索引:在表中的单个字段上创建索引

多列索引:在表的多个字段创建一个索引

空间索引:使用SPATIAL参数,空间索引只能建立在空间数据类型上,只有MyISAM存储引擎支持,且索引字段必须非空。