mysql学习(2)索引的本质

问题:SQL查询慢怎么办?

优化手段,加索引。mysql

索引是帮助MYSQL高效的获取数据的排好序数据结构。sql

问题:索引结构为何使用Btree而不使用二叉树,红黑树或者HASH结构?

二叉树的特性,右边子节点的值大于父节点,且左边子节点的值小于父节点数据库

二叉树:使用二叉树来作索引的数据结构,当索引值递增的时候,二叉树也会不断地增长右子节点 ,那么在查找索引的时候,所作的IO操做,等同于没有索引逐行查找数据的IO操做。数据结构

红黑树:平衡二叉树。随着数据量增大,树的高度也会变高。2的N次方=数量量(假设100万),那么N至少也是50,那么树的高度也是50,若是数据在子叶节点上,那么至少要通过50次的IO操做,才能找到数据。oracle

HASH:散列表结构,key不适合排序,并且数据是散列的分布的,不利于IO读写。性能

BTree:一个节点上,横向扩展。即一个节点上,能够存储多个元素(Degree),且每一个元素,均可以有子节点,叫作多叉树。优化

  • 度(Degree)-节点的数据存储个数
  • 叶节点具备相同深度
  • 叶节点的指针为空
  • 节点中的数据KEY从左至右递增排列

    以5阶B树举例ui

B+Tree(Btree变种)spa

  • 非叶子节点不存储data,只存储key,能够增大度(Degree)-节点的数据存储个数
  • 叶子节点不存储指针
  • 叶子节点增长了顺序访问指针,提升区间访问的性能

以5阶B+树举例指针

问题:Btree和B+Tree的区别?

  • Btree每一个节点,都包含了key和data,而B+tree只有叶子节点保存了key和data,其余节点,只保存了key,方便增大度的个数
  • B+tree的叶子节点之间, 增长了指针,提升了查询区间的性能,不须要像Btree同样每次都从根节点开始查找
  • Btree中,父节点和叶子节点,关键字的字段值不会冗余,而B+tree会冗余的存储关键的索引值,即父节点和叶子结点都存在相同的关键值

MyISAM索引实现(非汇集)

MyISAM索引文件和数据文件是分离的。它是针对建表的,而不是针对数据库的,既同一个数据库能够多种类型的表,myISAM和innoDB。

在mysql的文件件中,会发现一个表有三个文件:

  • test_table_myisam.frm // 存储表的结构,表的定义
  • test_table_myisam.MYD // 存储表的数据
  • test_table_myisam.MYI // 存储表的索引文件

myisam存储引擎是非汇集索引,因此在MYI的文件中,以B+tree的数据结构存储了表的索引信息,而索引内容中的data,是指向数据的在MYD文件中的地址。

在myisam存储引擎中,主键索引使用了B+tree,而辅助索引,非主键索引,也一样根据字段的值,使用了B+tree结构来存储。

innoDB索引实现(汇集)

  • 表数据文件自己就是按B+Tree组织的一个索引结构文件

   

  • 汇集索引 定义:叶节点包含了完整的数据记录
  • 为何innoDB表必须有主键,而且推荐使用整形的自增主键?
  • 为何非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)

在mysql的文件件中,会发现一个表有两个文件:

  • test_table_myisam.frm  // 存储表的结构,表的定义
  • test_table_myisam.ibd  // 存储表的索引+数据

在innoDB存储引擎中,辅助索引、非主键索引都不是汇集索引。

问题:为何B+tree比Btree快?

树的高度h,影响了查找效率,由于从根节点开始,每次查找下一个节点,均可能须要一次IO读写。因此增长非叶子节点的度,能够有效提升查询效率。而CPU从磁盘上读取数据到内存中,最小单元是页,一页读取的最小数据是4KB,而CPU一次IO,读取的数据是一页的整数倍,且最大值也有限制。而mysql在底层,设置的大小是16KB。因此B+TREE要把数据放在叶子节点,因此非叶子几点,就能够增长更多的节点数。而Btree节点和数据是保存在一块儿的,因此非叶节点的节点数,要比B+tree少,树的高度就比B+tree高。

问题:为何MYSQL页文件默认的配置是16KB?

咱们假设一行的数据是1K,那咱们一页的数据,就能存储16行数据,也就是一个叶节点能够存储16条记录;再来看非叶节点,假设ID是bigint类型,那么长度为8B,指针大小在InnoDB源码中为64(6B),一共就是14B,那么一页里面就能够存储16K/14=1170个(主键+指针)

那么一颗高度为2的B+树能存储的数据为:1170*16=18720条,一颗高度为3的B+树能够存储1170*1170*16=21902400(千万条)

缘由就是16KB就足够应对千万条表记录了。

问题:为何innoDB表必须有主键,而且推荐使用整形的自增主键?

         使用innoBD存储引擎时,要创建主键索引,若是咱们没有主动建立索引,那么innoDB会自动帮咱们创建主键索引。innoDB会在咱们建立的表里找一列惟一的,能够表明主键的字段来建立主键索引,若是没有这样的字段,innoDB会默认加一列字段,来建立主键索引。有点相似oracle中的rowId。为何要推荐整形并且自增的字段当作主键?为何建议使用整形类型,由于若是使用uuid做为主键索引,uuid类型比整数类型大,为了方便IO操做一次读取4个页的数据(mysql默认16KB,一页是4KB),意味索引的非叶子节点上的关键字要比使用整数类型的关键字数量小,那么B+tree的高度就可能增长,那么读取叶子节点上的数据的IO操做次数就增长了。那么查找的效率就低了。为何要自增,由于当新纪录插入时,主键自增的话,在B+tree中插入节点比较方便,而使用uuid为主键,新纪录的uuid不必定比前面的uuid大,可能会将新纪录插在靠前面的叶子节点中,叶子节点满了,会取中间的关键字向上存放到父节点中,可能会形成树的分裂,微观上性能就比自增的差。

相关文章
相关标签/搜索