MySQL数据库索引的使用以及索引失效问题的解决方法

MySQL索引的使用以及索引失效问题

索引是数据库表中字段的索引,所谓的索引就是在表的字段上添加的,每个字段都可以添加索引来提高查找效率,也可以多个字段联合添加一个索引。参考字典的实现,索引相当于字典的目录,通过目录缩小查找范围。

在任何数据库当中主键都会自动添加索引对象;在任何数据库当中,任何一张表的任何一条记录在实际硬盘存储上都有一个硬盘的物理存储编号;不管索引存储在哪里,索引在MySQL当中的都是一个树的形式存在。

索引的实现原理:就是缩小扫描的范围,避免全表扫描。

什么时候考虑添加索引?

  • 条件1:数据量庞大(到底多么庞大算庞大,这个需要测试,因为每一个硬件的环境不同)
  • 条件2:该字段经常出现在where的后面,以条件的形式存在,也就是说这个字段总是被扫描
  • 条件3:该字段很少的DML(insert ,delete,update)操作。(因为DML之后索引需要重新排序)

建议不要随意添加索引,因为索引也是需要维护的,太多的话反而降低系统的性能。

建议通过主键查询,建议通过unique约束的字段进行查询,效率是比较高的

索引的类型:单列索引、组合索引和全文索引

单列索引

  1. 主键索引,数据库表的主键字段会自动创建索引
  2. 唯一索引,当某个列添加了Unique约束,它会自动创建唯一索引,要求值必须是唯一的
  3. 普通索引,给普通字段添加索引就是普通索引

组合索引

  1. 多个字段合起来创建一个索引,只有当查询条件中使用了组合索引的第一个字段,索引才会被使用,使用组合索引是遵循最左前缀原则。

索引的使用

为了提高查询的效率

索引的创建和删除

  1. 创建索引

    create index 要创建的索引名 on 要创建索引的表名(要创建索引的字段)

  `create index  MY_INDEX_01 on table_01(field)`
  1. 删除索引

    drop index 要删除的索引名 on要删除的索引所在的表名

   drop index MY_INDEX_01 on table_01

索引失效的情况以及对应的解决方案

MySQL索引失效是一个常见的性能问题,它会导致查询效率下降,甚至影响整个系统的稳定性。因此我们需要了解索引失效的原因和解决方法,避免在编写SQL语句时犯一些低级错误。同时,我们也需要定期检查和优化索引的设计和使用情况,确保索引能够发挥最大的作用。

  1. **模糊查询以%开头。**select * from emp where ename like ‘%T’;

    如果查询条件中使用了like关键字,并且模糊匹配的字符串以%开头,会导致索引失效。因为以%开头的模糊匹配无法确定索引列的起始位置,所以无法利用索引进行快速查找。解决方法是尽量避免使用以%开头的模糊匹配,或者使用覆盖索引(只包含索引列的查询)

  2. 查询条件使用了OR关键字

    因为or关键字只满足一个条件就可以,因此只要有一个列不是索引列,其他索引列也就没有意义了,就会进行全表扫描

    解决方案:不建议使用OR关键字,可以使用UNION联合查询

  3. **对索引列使用函数 ** SELECT * FROM sys_user WHERE LENGTH(user_id) = 3

    如果查询条件中对索引列进行了函数调用或运算,那么会导致索引失效。

    因为索引保存的是索引字段的原始值,而不是经过函数计算后的值,

    解决方案:尽量避免对索引列使用函数;或者,(建立基于函数的索引)MySQL8.0开始增加了函数索引,也就是针对该函数计算后的值建立一个索引,这样就可以通过扫描索引来查询数据了。

  4. 对索引进行表达式计算 select * from sys_user where user_id+1 =3;

    解决方案: select * from sys_user where user_id =3-1;

    索引保存的是索引字段的原始值,而不是运算后的值,尽量避免对索引列进行运算;或建立基于运算的索引;

  5. 索引列隐式类型转换

    如果查询条件中数据类型和索引列的数据类型不一致,Mysql会进行隐式类型转换,导致索引失效。例如,如果索引列phone是varchar类型,而查询条件是数字类型,MySQL会将索引列转换为数字类型进行比较,导致索引失效。

    MySQL在遇到字符串与数字的比较的时候,会自动把字符串转为数字然后进行比较

    SELECT * FROM sys_user WHERE phone = 18200000000 ;相当于执行:SELECT * FROM sys_user WHERE CAST(phone AS UNSIGNED) = 18200000000 ;这就是在索引上使用了函数,会导致索引失效。

    假如索引字段user_id是bigint类型,SELECT * FROM sys_user WHERE user_id = "1" ;相当于执行:SELECT * FROM sys_user WHERE user_id = CAST("1" AS UNSIGNED) ;函数作用在查询参数上,而并没有作用在索引字段上,所以索引有效。

  6. 联合索引违反了最左前缀原则

    多个普通字段组合在一起创建的索引叫做联合索引(组合索引)

    联合索引的使用需要遵循最左匹配原则,也就是按照最左优先的方式进行匹配。

    例如创建一个(A,B,C)联合索引,那么查询条件要是以下几种,就可以匹配上联合索引:

   where a = 1
   where a = 1 and b = 2
   where a = 1 and b = 2 and c = 3

需要注意的是,因为查询优化器,A字段在where语句中的顺序不重要,但必须要有A字段。

解决方案:尽量按照最左匹配原则来使用联合索引,并且将区分度高的列放在前面。

  1. 用is null和is not null没注意字段是否允许为空

    如果字段不允许为null,则is null 和is not null这两种情况索引都会失效。

    如果字段允许为空,则is null走ref类型的索引,isnot null走range类型的索引。

  2. 特别说明,索引失效除了上述常见的原因外,MySQL通过索引扫描的行记录超过全表的10%-30%左右,优化器也可能不会走索引,自动变成全表扫描。

索引失效的常见误区

  1. 使用not in会导致索引失效

    使用not in并非绝对不走索引,MySQL查询优化器会根据当前表的情况选择最优解。)

    MySQL5.7和5.8效果不同,5.7这种情况SQL执行结果是全表扫描,5.8中使用了range类型索引。

  2. 使用不等于号(!=,<>)会导致索引失效

    mysql5.7和5.8不同的版本效果不一样,5.7中这种情况sql执行结果是全表扫描,而5.8中使用了 range 类型索引。

    5.7中如果想使用索引该怎么办呢?答案:使用大于和小于代替不等于。

索引设计建议

  • 优先使用唯一索引,能够快速定位

  • 为常作为查询条件的字段建立索引

  • 为排序、分组和联合查询字段建索引

  • 一张表的索引数量不要超过5个

  • 表数据量少的情况下可以不用建索引

  • 尽量使用占用空间小的字段建索引

  • 删除没有用的索引,因为它会占一定的空间

  • 区分度高的字段适合创建索引

    (比如用户表,生日字段比性别的区分度高,更适合创建索引)

  • 频繁更新的字段不适合创建索引

    (更新字段的过程中需要维护B+树索引结构,需要频繁地更新索引文件,性能较差)

你可能感兴趣的:(mysql,数据库,java)