问题一:关于数据库索引

什么是索引?索引的种类?

索引是帮助数据库高效获取数据的数据结构,是基于数据库表创建的,包含一个表中某些列的值以及记录对应的地址,并且把这些值存储在一个数据结构中。最常见的就是使用哈希表、B+树作为索引,项目中我们使用InnoDB引擎,默认的是B+树。

什么情况下创建索引?

一般来说,在WHERE和JOIN中出现的列需要建立素引,因为MySQL只对<,<=,>,>=,BETWEEN, IN,以及某些时候的LIKE才会使用索引(以通配符%和_开头作查询时,MySQL不会使用索引)通常会根据慢查询日志来优化 SQL以及判断是否建索引。

查询更快、占用空间更小

  1. 适合索引的列是出现在where子句中的列,或者连接子句中指定的列
  2. 基数较小的表,索引效果较差,没有必要在此列建立索引
  3. 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果搜索词超过索引前缀长度,则使用索引排除不匹配的行,然后检查其余行是否可能匹配。
  4. 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。
  5. 定义有外键的数据列一定要建立索引。
  6. 更新频繁字段不适合创建索引
  7. 若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
  8. 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
  9. 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
  10. 对于定义为text、image和bit的数据类型的列不要建立索引。

在创建索引时,怎样考虑多个字段之间的顺序的?

在创建多列索引时,我们根据业务需求,where子句中使用最频繁的一列
放在最左边,因为MySQ索引查询会遵循最左前缀匹配的原则,即最左
优先,在检索数据时从联合素引的最左边开始匹配。所以当我们创建:
个联合索引的时候,如(key1,key2,key3),相当于创建了 (key1)
(key1,key2)和(key1,key2,key3)三个索引,这就是最左匹配原则。

关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

在业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。
慢查询的优化首先要搞明白慢的原因是什么?是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?慢查询参考

所以优化也是针对这三个方向来的:

  • 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
  • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
  • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

为什么使用B+树?

由于索引是存在于磁盘中,当索引非常大的时候,比如达到几个G的时候,无法一次加载到内存中,所以数据库中索引使用的是查找效率更高的树形结构。B+树是平衡多路查找树,是为磁盘等外存储设备设计的一种平衡查找树。

系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,InnoDB存储引擎中有页 (Page) 的概念,页是其磁盘管理的最小单位。InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size设置页的大小,InnoDB在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置这将会减少磁盘IO次数,提高查询效率。

B+树使用有序数组链表+平衡多叉树改良了B树的有序数组+平衡多叉树;B+树的关键字全部存放在叶子节点中,非叶子节点用来做索引,而叶子节点中有一指针指向一下个叶子节点。做这个优化的目的是为了提高区间访问的性能。

举个例子?

数据库索引采用B+树的主要原因是B树在提高了磁盘IO性能的同时并没有解决元素遍历效率低下的问题。正是为了解决这个问题,B+树应运而生。B+树只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,也是B+树的优势所在。

例如:要查 5-10之间的,B+树一把到5这个标记,再一把到10,然后串起来就行了。而B树在找到第一个符合条件的数字5后,访问完第一个关键字所在的块后,得遍历这个B树,获取下一个块,直到遇到一个不符合条件的关键字。遍历的过程是比较复杂的。

什么是B+树?

B+树的演变要从二叉树开始,可参考B+树的演变。前面有提到,系统从磁盘读取数据到内存的时候是以磁盘块为基本单位,将磁盘块中的数据一次性的读取出来的。如果是二叉树,如图(二叉树1)每一个节点只存储一个键值对,如果是海量的数据的话,那么就会有海量的节点,那么如果要检索出需要的数据,可能就要进行多次的IO,是会导致效率低下的。
这时候就引入了B树(BalanceTree),每一个节点成为页(page),mysql的数据读取单位也就是页。相对于平衡二叉树来说,每一个节点存储了更多的键值和数据,同时,每一个节点拥有更多的子节点,称为“阶”,高度也就相对的比较低,所以,B树读取磁盘的IO次数也会大大的减小,数据查找效率也会高。
B+树的非叶子节点上是不存储数据的,仅存储键值,因为数据库中页的大小是固定的(innodb每个页的大小是16kb,当然可以通过参数进行配置)不存储数据,就可以存储更多的键值,树就会更矮,更胖一些,B+树的阶数是等于键值的数量。如果B+树的一个节点可以存放1000个键值的话,那么就可以存储大约10亿的数据,根节点是常驻于内存之中的,所以只需要两次磁盘的IO就可以搞定。因为B+树的数据都是按照顺序进行排列的,所以进行范围查找,排序查找,分组查找以及去重都会很快。而B树都是在各个节点上,要困难一些。

二叉树1
B树
B+树

B+树和hash索引比较起来有什么优缺点?

哈希索引适合等值查询,但是无法进行范围查询;哈希索引没办法利用索引完成排序以及like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);哈希索引不支持多列联合索引的最左匹配规则;B+树索引的关键字检索效率比较平均,哈希索引如果有大量重复键值的情况下,哈希索引的效率会很低,可能存在哈希碰撞问题。

B+树叶子节点都可以存什么东西?

InnoDB的B+树可能存储的是整行数据,也有可能是主键的值,索引B+树的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引。而索引B+树的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引。

Innodb和myisam引擎及索引学习参考

聚簇索引和非聚簇索引在查询时有什么区别?

主键索引查询只会查一次,而非主键索引需要回表查询多次,通过覆盖索引也可以只查询一次,覆盖索引指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。
MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。

聚簇索引VS非聚簇索引

聚集索引(聚簇索引):以InnoDB 作为存储引擎的表,表中的数据都会有一个主键,即使你不创建主键,系统也会帮你创建一个隐式的主键。

非聚集索引(非聚簇索引):以主键以外的列值作为键值构建的 B+ 树索引,我们称之为非聚集索引。

缓存知识介绍
一次IO读写,可以获取到16K(需要看操作系统中的配置)大小的资源,读取到的数据区域为Page(页)。当需要查询某个索引的B+树结构的时候,某些页被加载到内存的缓存区域中,查询操作会在内存里操作,而不用再次进行IO操作了。当要查询的行数据不在缓存里,才会触发新的IO操作。
通过上面的缓存知识来看,如果数据存放的位置是相对连续的,则缓存命中率会很高。而聚簇索引正好就是在磁盘上连续存放的。因为MyISAM的主索引并非聚簇索引,那么他的数据的物理地址(硬盘数据区的编号)相对于聚簇索引是比较凌乱的,拿到这些物理地址,按照合适的算法进行I/O读取,于是开始不停的寻道,不停的旋转,且存储地址跨度过大,也容易导致缓存命中率低。

聚簇索引的优缺点

优点:
1.数据访问更快,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快。聚簇索引对于主键的排序查找和范围查找速度非常快

缺点:
1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。
2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。
3.二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。

以下参考自 链接

myisam的主索引和次索引都指向物理行(磁盘位置)。
innodb的主键下存储该行的数据,此索引指向对主键的引用。

myisam的索引存储图如下,可以看出,无论是id还是cat_id,下面都存储有执行物理地址的值。通过主键索引或者次索引来查询数据的时候,都是先查找到物理位置,然后再到物理位置上去寻找数据。

myisam的索引查询示意图

innodb的索引存储图如下,我们会发现,主键索引下面直接存储有数据,而次索引下,存储的是主键的id。通过主键查找数据的时候,就会很快查找到数据,但是通过次索引查找数据的时候,需要先查找到对应的主键id,然后才能查找到对应的数据。

innodb的索引查询示意图

你可能感兴趣的:(问题一:关于数据库索引)