索引是帮助mysql 高效查询数据的排好序的数据结构。
select * from t where t.col2 = 89
就这条sql 来说,如果这张表没有索引的话,会根据这张表的数据逐行的进行查询,每查询一次会跟当前数据进行比对一次,会产生跟磁盘的io 交互。如果数据量特别大的情况下,会特别影响效率。
索引的数据结构
- 二叉树
- 红黑树
- Hash表
- B-Tree
二叉树
如果给col2 加上索引,放到二叉树里
每个节点其实是一个key(索引)- value (索引所在行的磁盘文件地址)的结构
二叉树有个特性,右下角的元素大于父元素,左下角的元素小于父元素。34 < 89 两次查询到结果。查到之后,把他里面的value 磁盘文件地址拿出来,根据磁盘文件地址直接找到数据。效率比逐行全盘扫描的效率高的多。(mysql真正的存储结构没有用到二叉树)
假设 col1 为索引字段。并且以二叉树来存储。
如果以数据类型是自增类型的数据,给他存储为二叉树的结构,他其实变成了一个链表的结构。查询 clo1= 6 的话,需要查询6次,数据量大的话会存在一定的问题,接近全表扫描,跟没建索引区别不大。
红黑树
红黑树其实本质还是一个二叉树,它的全名叫做二叉平衡树,当一边比另一边高太多,他有自动平衡的功能。
如下图 (红黑树 自动平衡功能)
数据结构可视化网 https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
如果在红黑树上查找col = 6 只需要三次,上一步我们使用二叉树需要六次,红黑树比二叉树又稍微优化了一点 (mysql 早起的索引有用到红黑树)
红黑树存在的一些弊端
层级可能比较多。如果一千万的索引,树的高度无法想象,数据量越大,树的高度会越高。如果我们刚好要查的数据在树的叶子节点,那需要查询的次数就越多(每查一次都是跟磁盘的一次交互)。
B-Tree
- 叶节点具有相同的深度,叶节点的指针为空
- 所有索引元素不重复
- 节点中的数据索引从左到右递增排列
B + Tree (B-Tree 变种)
举个例子:
我们要查找30,首先把根节点所有的字段放到内存中,然后在内存中做比对,因为他是从左到右依次递增,因此我们可以折半查找,找到在15-56之间,继续在分叉节点进行查找,整个查找过程经历三次的磁盘io。在内存比较耗费的时间相比跟磁盘io
交互的时间对比,几乎可以忽略不计。
B + tree
- 所有元素包括节点之间都是从左到右依次递增
- 非叶子节点不存储data,只存储索引,可以放更多的索引
- 叶子节点包含所有索引字段
- 叶子节点用指针连接,提高区间访问的性能
也就是说,叶子节点是由整张表的所有索引元素以及索引所在行的磁盘文件地址,非叶子节点就是一些冗余索引
B + Tree 是如何在树的高度可控的情况下,能存储大量的元素。现在有一千万数据,怎么做到让树的高度 h 小于等于 4 。
mysql 底层的数据结构用了 B+Tree 的结构,他是把根节点分配了16kb,这里我们可以去数据查一下
SHOW GLOBAL STATUS LIKE 'INNODB_page_size'
当我们这颗树放满了,叶节点大概可以容纳多少个元素。
假设现在以主键索引来维护这棵树,一般会用bigint、int,假设我们用bigint,mysql 里面大概是8 byte,根节点大概是16kb, 16kb * (8+6)约等于1170 个索引元素,叶子结点是16kb,除了索引元素还有data 元素,1170 * 1170 * 16 约等于两千多万…
Hash
- 对索引的key 进行一次hash 计算就可以定位出数据存储的位置
- 很多时候hash 索引比 b+tree 更高效
- 仅能满足 “=” “in”,不支持范围查询
- hash 冲突问题
mysql 怎么处理慢查询,对慢查询都怎么优化?
在业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。
慢查询的优化首先要搞明白慢的原因是什么?是查询条件没有命中索引?是load了不需要的数据列? 还是数据量太大?
所以优化也是针对三个方向来的 :
- 首先分析语句。看看是否load 了 额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
- 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
- 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。
索引对数据库的性能影响:
- 普通索引 :允许被索引的数据列包含重复的值。
- 唯一索引:可以保证数据记录的唯一性。
- 主键:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于标识一条记录,使用关键字 primary key 来创建。
- 联合索引:索引可以覆盖多个数据列,如像index(cola,clob)索引
- 全文索引:通过建立倒排索引,可以极大的提升检索效率,解决判断字段是否包含的问题,是目前搜索引擎使用的一种关键技术,可以通过alter table table_name add fulltext (col) 创建全文索引。
索引可以极大的提高数据的查询速度。
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。 但是会降低插入、删除、更新表的速度,因为在执行写操作时,还要操作索引文件
索引需要占物理空间,除了数据表的数据空间之外,每一个索引还要占一定的物理空间,如果建立聚簇索引,那么需要的空间就会更大,如果非聚簇索引很多,一旦聚簇索引改变,那么所有非聚簇索引都会跟着改变。