1、什么是索引?
索引是一种数据结构,帮助我们快速的进行数据查找。
2、索引是什么样的数据结构?
索引的数据结构与使用的存储引擎实现有关,在MySQL中使用较多有Hash索引和B+树索引等,而我们经常使用的InnoDB存储引擎默认的索引实现为B+树索引。
3、Hash索引和B+树索引有什么区别或者说优劣呢?
先说hash索引
hash索引底层就是hash表,进行数据查找时,执行一次hash函数就可以获取相应的键值,之后进行回表查询获取实际的数据。
hash索引进行等值查询更快,但无法进行范围查询、不能排序、不能使用组合索引的最左前缀匹配。
原因是因为hash索引经过hash函数建立索引后,索引顺序无法与原顺序保持一致。
hash索引任何时候都避免不了回表查询。
然后说B+树索引
B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据。
B+树支持范围查询、支持排序、支持组合索引的最左前缀匹配。
原因是因为B+树的的所有节点皆遵循左节点小于父节点,右节点大于父节点。
B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询.不需要回表查询。
4、什么是聚簇索引(什么是主键索引,和普通索引有什么区别)?
在B+树索引中,聚簇索引的叶子节点包含所有字段,非聚簇索引(也叫二级索引)只包含索引字段+主键字段(或主键指针)。在InnoDB中,只有主键索引是聚簇索引,如果没有主键则挑选一个唯一键建立聚簇索引,然后没有唯一键则隐式生成一个键来建立聚簇索引。
5、什么是覆盖索引?
当查询使用聚簇索引或查询所要求的全部字段都命中了索引,不需要回表查询,那么就是覆盖索引。
6、在建立索引都有哪些考虑因素?
首先考虑的是字段的使用频率,经常作为条件去进行查询的字段比较合适。并且表数据较多的时候,值分布大(选择性较好的),创建索引会明显地提高查询速度。
(经常与其他表进行连接的表,在连接字段上应该建立索引)
然后需要建立组合索引的话,还需要考虑遵循他的最左前缀匹配。
此外还需要考虑其他方面,如过多的建立索引会导致对插入、更新、删除的开销,减低处理数据的性能。
7、组合索引是什么?为什么需要遵循他的最左前缀匹配
Mysql可以使用多个字段同时建立一个索引,叫组合索引。
具体原因是:MySQL在建立组合索引时是先按第一列进行排序,然后在第一列排好序的基础上再对第二列排序,然后没有第一列直接访问第二列的话,那肯定是无序的,直接访问后面的列也就用不到索引了。
8、创建的索引有没有被使用到,或者说怎么才知道这条语句运行很慢的原因?
MySQL提供了explain命令来查看语句的执行计划,MySQL在执行语句之前,会将该语句从查询优化器过一遍,之后会拿到对语句的分析,也就是执行计划,其中包含了许多信息,可以通过其中对索引有关的信息来分析是否命中了索引,例如possibe_key、key、key_len、type等字段,分别说明了此语句可能会使用到的索引,实际使用到的索引以及使用的索引长度,还有就是访问类型,表示在表找到所需行的方式,他有几个值,性能从好到差分别是 const、eq_ref、ref、range、index、All。
9、那么在哪些情况下会发生创建了索引但在查询时候没有用到呢?
- 索引字段是 字符串类型,查询条件是数字型的,类型不匹配索引失效
- 在索引列进行运算操作
- where条件 以%开头like模糊查询
- where条件not 、 !=、<> 、not in不使用索引
- where条件or 两边的字段都需要带有索引,否则索引失效
- 使用了范围查找(>、<、between、like)、查出的量大不使用索引【后面的字段不使用索引】
- 组合索引没有遵循最左原则
- mysql评估认为全表扫描会更快时不使用索引
- 使用 is null、is not null 有时索引失效(值少的时候)
10、对语句是怎么优化过的
在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,并开启一段时间的慢查询记录开关,来得到查询语句。
慢查询的优化首先要搞明白慢的原因是什么?是查询条件没有命中索引,还是查询出不需要的数据列,还是数据量太大了。
所以优化针对这三个方向来。 - 首先分析语句,是否加载了额外的数据,可能查询多余的行并且抛弃掉了,可能查询并不需要的列,对语句进行分析以及重写。
- 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或修改索引,使其语句可以尽可能的命中索引。
- 如果对语句的优化已经无法进行,可以考虑表中的数据是否过大,如果是的话可以进行横向或纵向的分表。
11、上面提到横向分表和纵向分表,可以分别举一个适合他们的例子吗? - 横向分表是按行分表.假设我们有一张用户表,主键是自增ID且同时是用户的ID.数据量较大,有1亿多条,那么此时放在一张表里的查询效果就不太理想.我们可以根据主键ID进行分表,无论是按尾号分,或者按ID的区间分都是可以的.
假设按照尾号0-99分为100个表,那么每张表中的数据就仅有100w.这时的查询效率无疑是可以满足要求的. - 纵向分表是按列分表.假设我们现在有一张文章表.包含字段id-摘要-内容.而系统中的展示形式是刷新出一个列表,列表中仅包含标题和摘要,当用户点击某篇文章进入详情时才需要正文内容.此时,如果数据量大,将内容这个很大且不经常使用的列放在一起会拖慢原表的查询速度.我们可以将上面的表分为两张.id-摘要,id-内容.当用户点击详情,那主键再来取一次内容即可.而增加的存储量只是很小的主键字段.代价很小.