mysql索引浅析

179 阅读5分钟

1、索引

提及数据库优化,大多面试者第一个要说的就是创建索引,但是深究之后,大家往往对索引理解不够深入,借此谈一下数据库索引。

索引之优劣

优点:减小了服务器需要扫描的数据量,提高了查询速度;

缺点:

1、创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加。

2、索引也需要占空间,我们知道数据表中的数据也会有最大上线设置的,如果我们有大量的索引,索引文件可能会比数据文件更快达到上线值。

3、当对表中的数据进行增加、删除、修改时,索引也需要动态的维护,降低了数据的维护速度。

**总结:**基于其优缺点,虽然索引的会提升数据库性能,但如果随意使用,也许会适得其反,所以我们需要深入理解索引,才能用好索引。

2、索引——数据结构

hash表

1、hash适用于等值查找,不适合范围查找;

2、有序数组在等值查询和范围查询中性能非常优秀,但是只适用于静态存储引擎,

二叉树:

1、树高太高了,取一次数据需要访问磁盘次数太多;

2、硬盘一页为4k,平衡二叉树不能很好利用磁盘特性;

B树:

1、一个磁盘块可以放多个数据,树高也降下来了,可以有效利用磁盘特性;

2、数据和索引在同一个节点上

B+树:

1、相比B树,数据都存放在叶子节点上,一个磁盘块上可以存放更多的数据,可以有效降低树高,减少磁盘访问次数;

2、B+树的数据之存在叶子节点,并且叶子节点之间存在双向指针,在进行范围查询遍历时,减少时间复杂度;

我们来总结一下b+树的特点:

1、有序性,方便检索和范围查询;

2、每个数据节点存储的是数据块,减少了树高,从而减少了磁盘的读取次数(寻址消耗)。同事又利用了磁盘的块存储 和 预读 特性,提升了IO读写性能;

3、叶子节点之间有双向指针连接,提高区间范围性能,范围查找;

4、利用跳表的特性,增加数据检索效率;

3、结合数据结构,重新认识索引失效场景

原则:

1、最左匹配原则;

2、基于成本(IO/CPU/内存)考虑:如果基于索引成本较高,那么就放弃使用索引。

例如:基于索引查询到的数据占全表数据的80%,那么全表扫描效率更高;

3、磁盘顺序读写性能更高,具有预读特性,猜测可能会使用到周边数据块的数据,会将周边数据块的数据一起读写;

4、了解数据库的一些概念,回表、覆盖索引、索引下推等概念,可以帮助写出高效的sql;

5、尽量少访问资源是数据库设计的重要原则之一,在使用数据库时,设计表时,尽量减少资源消耗为目标;

6、减少索引的大小,有助于内存中可以存放更多的索引,减少磁盘读写;

1、不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
EXPLAIN SELECT * FROM employees WHERE name = 'LiLei'; 使用索引
EXPLAIN SELECT * FROM employees WHERE left(name,3) = 'LiLei'; 未使用索引
原因:B+树上存储的是数据,当使用到函数,无法比对;

存储引擎不能使用聚合索引(index_name_age_position)中范围条件右边的列
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager'; 使用索引
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age > 22 AND position ='manager'; 未使用索引
原因:因为索引前缀匹配,索引只能拿确定的内容进行匹配。第二个sql只能使用到name和age字段;

尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少select *语句
EXPLAIN SELECT name,age FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager'; 只查询索引不用查询具体的数据,效率更高
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 23 AND position ='manager';
原因:如果查询的字段都在索引里面,就不需要回表,直接将索引中的数据返回即可
如果定义了索引长度,那么覆盖索引会失效原因:无法确实查询到的是完整的数据,所以必须回表查询

mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
原因:使用不等号查询的数据量巨大,假如基于索引查询,寻址频率比较高,基于索引范围没有全表扫描,顺序读写效率高

is null,is not null 也无法使用索引
原因:由于不将空值放在B+树上,所以我发使用到索引

like以通配符开头('$abc...')mysql索引失效会变成全表扫描操作
原因:最左匹配

字符串不加单引号索引失效,防止发生隐士类型转换
EXPLAIN SELECT * FROM employees WHERE name = '1000';
EXPLAIN SELECT * FROM employees WHERE name = 1000;
原因:我理解和使用函数的原因是一样的

or 只有两边都有索引才走索引,如果都没有或者只有一个是不走索引的
原因:由于是or关系,所以如果一边走索引,一边不走索引,带来的代价就是需要全表扫描一遍,再基于所以查询一边,然后求并集,消耗更大,不如直接走全表扫描

in操作能避免则避免,若实在避免不了,需要仔细评估in后边的集合元素数量,控制在1000个之内
原因:寻址消耗>全表扫描。

union all 不去重复,union去重复,union使用了临时表,应尽量避免使用临时表

order by如果根据多个值进行排序,那么排序方式必须保持一致,
要么同时升续,要么同时降续,排序方式不一致不走索引
原因:联合索引是将多个字段进行拼接存储的,如果排序方式不一致,无法检索

数据库编码: 采用utf8mb4而不使用utf8
原因:数据库的编码格式与java不同,utf8使用的是4个字节,对于表情包之类的占用4个字节无法存储,所以建议使用utf8mb4编码