索引的出现其实就是为了提升数据查询的效率,就像书的目录同样。mysql
索引模型有三种常见、也比较简单的数据结构分别是哈希表、有序数组和搜索树。sql
哈希表数据库
哈希表是一种以键 - 值(key-value)存储数据的结构,咱们只要输入待查找的值即 key,就能够找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个肯定的位置,而后把 value 放在数组的这个位置。数组
适用于只有等值查询的场景,好比 Memcached 及其余一些NoSQL 引擎。性能优化
有序数组数据结构
有序数组在等值查询和范围查询场景中的性能就都很是优秀。函数
这里咱们假设身份证号没有重复,这个数组就是按照身份证号递增的顺序保存的。这时候若是你要查 ID_card_n2 对应的名字,用二分法就能够快速获得,这个时间复杂度是O(log(N))。性能
若是仅仅看查询效率,有序数组就是最好的数据结构了。可是,在须要更新数据的时候就麻烦了,你往中间插入一个记录就必须得挪动后面全部的记录,成本过高。因此,有序数组索引只适用于静态存储引擎,好比你要保存的是 2017 年某个城市的全部人口信息,这类不会再修改的数据。优化
二叉搜索树spa
二叉搜索树的时间复杂度是 O(log(N))。树能够有二叉,也能够有多叉。多叉树就是每一个节点有多个儿子,儿子之间的大小保证从左到右递增。二叉树是搜索效率最高的,可是实际上大多数的数据库存储却并不使用二叉树。其缘由是,索引不止存在内存中,还要写到磁盘上。
为了让一个查询尽可能少地读磁盘,就必须让查询过程访问尽可能少的数据块。那么,咱们就不该该使用二叉树,而是要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。
在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。
每个索引在 InnoDB 里面对应一棵 B+ 树。
假设,咱们有一个主键列为 ID 的表,表中有字段 k,而且在 k 上有索引。
假如建表语句以下:
mysql> create table T( id int primary key, k int not null, name varchar(16), index (k))engine=InnoDB;
表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图以下。
主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。
根据上面的索引结构说明,咱们来讨论一个问题:基于主键索引和普通索引的查询有什么区别?
也就是说,基于非主键索引的查询须要多扫描一棵索引树。所以,咱们在应用中应该尽可能使用主键查询。
为何主键须要自增呢?
这样每次插入一条新记录,都是追加操做,都不涉及到挪动其余记录,也不会触发叶子节点的分裂,性能高得多。
并且主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。
因此,从性能和存储空间方面考量,自增主键每每是更合理的选择。
最左前缀原则
因为覆盖索引能够减小树的搜索次数,显著提高查询性能,减小回表,因此使用覆盖索引是一个经常使用的性能优化手段。
在创建联合索引的时候,如何安排索引内的字段顺序?
第一原则是,若是经过调整顺序,能够少维护一个索引,那么这个顺序每每就是须要优先考虑采用的。
,若是既有联合查询,又有基于 a、b 各自的查询呢?查询条件里面只有 b 的语句,是没法使用 (a,b) 这个联合索引的,这时候你不得不维护另一个索引,也就是说你须要同时维护 (a,b)、(b) 这两个索引。
这时候,咱们要考虑的原则就是空间了。好比上面这个市民表的状况,name 字段是比 age 字段大的 ,那我就建议你建立一个(name,age) 的联合索引和一个 (age) 的单字段索引。
索引下推
若是如今有一个需求:检索出表中“名字第一个字是张,并且年龄是 10 岁的全部男孩”。那么,SQL 语句是这么写的:
mysql> select * from tuser where name like '张 %' and age=10 and ismale=1;
MySQL 5.6 以前,只能从 ID3 开始一个个回表。到主键索引上找出数据行,再对比字段值。
而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 能够在索引遍历过程当中,对索引中包含的字段先作判断,直接过滤掉不知足条件的记录,减小回表次数,以下图所示: