MySQL索引是一种数据结构,用于快速访问数据库表中的数据。索引可以提高数据库的查询性能,减少查询所需的时间,因为它们允许MySQL在查询期间快速定位表中特定的行,而不必扫描整个表。
MySQL支持多种类型的索引,包括:
B-Tree索引:B-Tree是MySQL中最常用的索引类型,它可以用于所有数据类型,包括字符串和数值类型。B-Tree索引对于等值查询和范围查询非常有效。
哈希索引:哈希索引可以快速定位特定的行,但只支持等值查询,不支持范围查询。
全文索引:全文索引可以用于对文本数据进行高效的全文搜索,例如文章、博客和评论等。
空间索引:空间索引可以用于存储和查询具有空间数据的表,例如地图和地理位置数据。
在MySQL中,可以为表中的一个或多个列创建索引。索引可以在创建表时定义,也可以在表已经创建后添加。但是,对于大型的表,应该仔细考虑哪些列需要索引,因为索引可能会导致写操作的性能下降,因为每次插入、更新或删除操作都必须更新索引。
**
什么时候索引会失效?
**
违反最左前缀原则
拿我们文章开始创建的联合索引为例,该联合索引的B+树数据页内的记录首先按照name字段进行排序,name字段相同的情况下,再按照phone字段进行排序。
所以,如果我们直接使用phone字段进行搜索,无法利用索引的顺序性。
EXPLAIN SELECT * FROM user_innodb WHERE phone = “13203398311”;
image-20220315165212944
EXPLAIN可以查看搜索语句的执行计划,其中,possible_keys列表示在当前查询中,可能用到的索引有哪一些;key列表示实际用到的索引有哪一些。
但是一旦加上name的搜索条件,就会使用到联合索引,而且不需要在意name在WHERE子句中的位置,因为查询优化器会帮我们优化。
EXPLAIN SELECT * FROM user_innodb WHERE phone = “13203398311” AND name = ‘蝉沐风’;
image-20220315165908904
使用反向查询(!=, <>,NOT LIKE)
MySQL在使用反向查询(!=, <>, NOT LIKE)的时候无法使用索引,会导致全表扫描,覆盖索引除外。
EXPLAIN SELECT * FROM user_innodb WHERE name != ‘蝉沐风’;
image-20220315190829963
LIKE以通配符开头
当使用name LIKE '%沐风’或者name LIKE '%沐%'这两种方式都会使索引失效,因为联合索引的B+树数据页内的记录首先按照name字段进行排序,这两种搜索方式不在意name字段的开头是什么,自然就无法使用索引,只能通过全表扫描的方式进行查询。
EXPLAIN SELECT * FROM user_innodb WHERE name LIKE ‘%沐风’;
image-20220315202339837
但是使用通配符结尾就没有问题
EXPLAIN SELECT * FROM user_innodb WHERE name LIKE ‘蝉沐%’;
image-20220315202531736
对索引列做任何操作
如果不是单纯使用索引列,而是对索引列做了其他操作,例如数值计算、使用函数、(手动或自动)类型转换等操作,会导致索引失效。
使用函数
EXPLAIN SELECT * FROM user_innodb WHERE LEFT(name,3) = ‘蝉沐风’;
image-20220315203446591
MySQL8.0新增了函数索引的功能,我们可以给函数作用之后的结果创建索引,使用以下语句
ALTER TABLE user_innodb ADD KEY IDX_NAME_LEFT ((left(name,3)));
再次执行EXPLAIN语句,此时索引生效
image-20220315204529598
使用表达式
EXPLAIN SELECT * FROM user_innodb WHERE id + 1 = 1100000;
image-20220315205336452
换一种方式,单独使用id,就能高效使用索引:
EXPLAIN SELECT * FROM user_innodb WHERE id = 1100000 - 1;
image-20220315205618100
使用类型转换
例1
user_innodb中的phone字段为varchar类型,实验之前我们先给phone字段创建个索引
ALTER TABLE user_innodb ADD INDEX IDX_PHONE (phone);
随便搜索一个存在的手机号,看一下索引是否成功
EXPLAIN SELECT * FROM user_innodb WHERE phone = ‘13203398311’;
image-20220315211631637
可以看到能使用到索引,现在我们稍微修改一下,把phone = '13203398311’修改为phone = 13203398311,这意味着我们将字符串的搜索条件改成了整形的搜索条件,再看一下还会不会使用到索引:
EXPLAIN SELECT * FROM user_innodb WHERE phone = 13203398311;
image-20220315212929411
显示索引失效。
例2
我们再看一个例子,主键id类型是bigint,但是在搜索条件中我估计使用字符串类型:
EXPLAIN SELECT * FROM user_innodb WHERE id = ‘1099999’;
image-20220315213426349