mysql索引
mysql索引分类
mysql索引分成以下几类:
- B+索引
- hash索引
- 全文索引
B+数索引
B+树索引分为聚集索引和非聚集索引(辅助索引)。聚集索引是通过表的主键来构建B+树,聚集索引不仅包括索引的值还包括其他列的相关信息。聚集索引中的记录是根据键值顺序存放的。聚集索引的非叶子节点存储的是<健值,索引>对。地址为指向下一层的指针,见下图B+数据结构。
在聚集索引中会存储key及指向下一节点的指针。
非聚集索引的叶子节点并不保存列的其他信息,其中叶子节点保存的是<键值,(记录)地址>,记录地址存在以下的形式。
- 记录的物理地址,页号:槽号:偏移量
- 记录的主键值
第一种是myisam存储B+树的存储方式,在myisam存储引擎中没有聚集索引。索引的记录并不放在B+树中,而是放在堆表。在myisam存储引擎中非聚集索引方式的主键索引和其他索引的区别在与该索引是否唯一的并且非空。
InnoDB存储引擎采用的B+数的聚集索引,他可以通过主键ID快速查找记录。聚集索引中所有记录都放在叶子节点。
不通存储引擎下的非聚集索引比较如下:
| 操作 | myisam | innodb |
|---|---|---|
| 读 | 所有的索引是非聚集索引,因此所有查询操作的开销均差不多 | 通过辅助索引只能查找到主键值,要查询完整记录还需要通过一次聚集索引 (这种查询方式也叫书签查找) |
| 写 | 所发生更新,则更新索引 | 仅主键值发生改变时,需要更新辅助索引 |
B+树在mysql下面存储结构
mysql的存储结构有tablespace、segement、extent,page。
mysql创建索引的时候会创建一个新的b+tree。
他会先为非叶子节点segement分配一个innode entry【用来管理数据文件中的segemnet】,再创建root page。将segement的位置记录到root page中,如何分配leaf segment的Inode entry。然后随之记录到root page。
一棵聚集索引B+树可以放多少行数据
前提:假设每一行数据大小为1K
- 计算叶子节点可以存储大小
上面有提到过mysql中存在page存储结构,一个page大小为16K。那么1个page最多可以存储16条记录。及在聚集索引下每个叶子节点最多可以存储16条记录。
- 计算非叶子节点个数
那么非叶子节点可以存储多少数据,假设主键ID为bigint类型,长度为8字节。在Innode中指针需要占用6个字节,这样一个关键字所占字节为(8+6)14字节。那么接下去就是一个page中能存放多少这样的单元,其实就代表有多少指针,即16kb/14b=1170。那么可以算出一棵高度为2的B+树,大概能存放1170*16=18720条这样的数据记录。
- 3阶B+数存储数量
根据同样的原理我们可以算出一个高度为3的B+树大概可以存放:1170117016=21902400行数据。所以在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次逻辑IO操作即可查找到数据。
B+树索引下一些索引失效问题
索引失效其实取决于B+树的一些特性
- 最左前缀原则
在B+树中的键值是按照组合索引的顺序排列的如(A,B,C)当你查找A=?and C=?的时候那么这个事实上只有A才会在B+树中查找到对应的关键值。而C无法使用B+树进行索引。
- like 以%开头
以%开通键值无法确定肯定无法在B+树中索引
- or语句前后没有同时使用索引
or 或查询,当中任意一个不建立索引,那么该字段无对应的索引就需要进行全表扫描
- 在索引列上使用 IS NULL 或 IS NOT NULL操作
B+树上任意一个关键字都不会为空所以该索引会失败
- 在索引字段上使用not,<>,!=。
B+上的查找是和关键字比较大小,查找到合适的范围,所以任意一种不等于符号都会导致索引失败
- 对索引字段进行计算/使用函数
计算之后会导致根本找不到对应的关键字
hash索引
hash索引使用场景不如B+树那么多,经过hash索引之后也一定会进行一次聚集索引。
hash索引是基于hash表的精准查询。对于每一行数据,存储引擎都会对所有的索引列计算一个hash code,并将的有的hash code存储在索引中,同时在哈希表中保存指向每个数据行的指针。
hash index中不支持范围查询,只支持等值查询。而且也不能进行部分索引匹配,因为索引的所有内容都要进行hash