索引法则--LIKE以%开头会导致索引失效进而转向全表扫描(使用覆盖索引解决)

1 准备数据

1.1 建表

DROP TABLE IF EXISTS staff;
CREATE TABLE IF NOT EXISTS staff (
id INT PRIMARY KEY auto_increment,
name VARCHAR(50),
age INT,
pos VARCHAR(50) COMMENT ‘职位’,
salary DECIMAL(10,2)
);
1.2 插入数据

INSERT INTO staff(name, age, pos, salary) VALUES(‘Alice’, 22, ‘HR’, 5000);
2 测试&Explain分析

2.1 有索引的情况下%的影响(提出问题)

2.1.1 建立索引

CREATE INDEX idx_nameAgePos ON staff(name, age, pos);
2.1.2 测试&Explain分析

Case#1:两边都是%

EXPLAIN SELECT * FROM staff WHERE name LIKE ‘%Alice%’;

结果:type=all,全表扫描

Case#2:左边是%

EXPLAIN SELECT * FROM staff WHERE name LIKE ‘%Alice’;

结果:type=all,全表扫描

Case#3:右边是%

EXPLAIN SELECT * FROM staff WHERE name LIKE ‘Alice%’;

结果:type=range,效果还可以。

对上面三个例子的总结:

都是 SELECT *
%在左边,即使有索引,也会失效
只有当%在右边时,才会生效
但问题是,生产环境中,就是要支持模糊查询(%在右边是不够的),一定要两边都是%来查询,这可咋办?

2.2 无索引情况下的查询汇总

2.2.1 删除索引

DROP INDEX idx_nameAgePos ON staff;
2.2.2 测试&Explain分析(主要为了和 2.3.2 节做对比测试)

Case#4:查询Id

EXPLAIN SELECT id FROM staff WHERE name LIKE ‘%Alice%’;

Case#5:查询name

EXPLAIN SELECT name FROM staff WHERE name LIKE ‘%Alice%’;

Case#6:查询age

EXPLAIN SELECT age FROM staff WHERE name LIKE ‘%Alice%’;

Case#7:查询 id & name

EXPLAIN SELECT id, name FROM staff WHERE name LIKE ‘%Alice%’;

Case#8:查询 name & age

EXPLAIN SELECT name, age FROM staff WHERE name LIKE ‘%Alice%’;

Case#9:查询 id & name & age

EXPLAIN SELECT id, name, age FROM staff WHERE name LIKE ‘%Alice%’;

Case#10:查询 id & name & age & salary (提示:salary 不在索引列中,后面会用上)

EXPLAIN SELECT id, name, age, salary FROM staff WHERE name LIKE ‘%Alice%’;

Case#11:查询 *

EXPLAIN SELECT * FROM staff WHERE name LIKE ‘%Alice%’;

从 Case#4 到 Case#11 可以看出,在没有索引的情况下,两边都使用 % 来查询,不管想查询哪个字段(包括查询Id),全部都是全表扫描。

2.3 有索引情况下的查询汇总

2.3.1 建立索引

CREATE INDEX idx_nameAgePos ON staff(name, age, pos);
2.3.2 测试&Explain分析

IndexCase#4:查询Id

EXPLAIN SELECT id FROM staff WHERE name LIKE ‘%Alice%’;

结果:使用上了索引(因为 name 有索引,同时查询的 Id 是主键肯定也有索引)

IndexCase#5:查询name

EXPLAIN SELECT name FROM staff WHERE name LIKE ‘%Alice%’;

结果:使用上了索引(因为查询条件和查询字段都是有索引的 name)

IndexCase#6:查询age

EXPLAIN SELECT age FROM staff WHERE name LIKE ‘%Alice%’;

结果:使用上了索引(因为查询条件的 name 以及查询字段的 age 都有索引)

IndexCase#7:查询 id & name

EXPLAIN SELECT id, name FROM staff WHERE name LIKE ‘%Alice%’;

结果:使用上了索引(因为查询条件的 name 以及查询字段的 id & name 都有索引)

IndexCase#8:查询 name & age

EXPLAIN SELECT name, age FROM staff WHERE name LIKE ‘%Alice%’;

结果:使用上了索引(因为查询条件的 name 以及查询字段的 name & age 都有索引)

IndexCase#9:查询 id & name & age

EXPLAIN SELECT id, name, age FROM staff WHERE name LIKE ‘%Alice%’;

结果:使用上了索引(因为查询条件的 name 以及查询字段的 id & name & age 都有索引)

IndexCase#10:查询 id & name & age & salary (提示:salary 不在索引列中)

EXPLAIN SELECT id, name, age, salary FROM staff WHERE name LIKE ‘%Alice%’;

结果:没有索引,type=all,全表扫描!(因为查询字段中多了个 salary 而 salary 不在索引列中)

IndexCase#11:查询 *

EXPLAIN SELECT * FROM staff WHERE name LIKE ‘%Alice%’;

结果:没有索引,type=all,全表扫描!(因为 * 包含 salary 而 salary 不在索引列中)

通过 IndexCase#4 到 IndexCase#11 可以看出,当真的需要两边都使用%来模糊查询时,只有当这个作为模糊查询的条件字段(例子中的name)以及所想要查询出来的数据字段(例子中的 id & name & age)都在索引列上时,才能真正使用索引,否则,索引失效全表扫描(比如多了一个 salary 字段)。我想,这应该就是 ‘覆盖索引(索引覆盖)’ 的本质吧。同时,这也能很好的证实 “尽量避免SELECT * 而是一一罗列出所需要查询的字段” 的道理吧,因为,搞不好 SELECT * 就多了一个字段,就导致了全表扫描。

3 结论

LIKE以%开头会导致索引失效;使用覆盖索引解决之

### 回答1: 非常抱歉,我的回答仍有误。实际上,在 SQL 中并有以 & 结尾的通配符,正确的通配符是以 % 或 _ 开头的。使用 % 通配符开头的模式导致索引失效,因为查询引擎无法利用索引进行优化,而使用 _ 通配符开头的模式可以利用索引进行优化。 对于以其他字符开头的模式,如果模式能够匹配到索引的前缀,那么索引可以被利用。需要注意的是,对于包含通配符的模式匹配,无论是以哪个字符开头,都涉及到性能问题。通配符的使用导致索引失效,因为无法确定哪些索引可以匹配,因此需要扫描整个表格。因此,我们在编写 SQL 查询时应该避免使用通配符,或者尽可能地减少通配符的使用,以提高查询性能。 ### 回答2: %开头时,索引是无效的。在SQL中,LIKE是用于模糊匹配的操作符。如果像这样以%开头,它将匹配到任何以特定字符开头的字符串。正常情况下,LIKE操作符通常以%结尾,以便匹配以特定字符结尾的字符串。 例如,如果我们使用LIKE操作符来查询以字母A开头的所有单词,我们使用以下查询: SELECT * FROM words WHERE word LIKE 'A%'; 这将返回所有以A开头的单词,如"Apple"和"Ant"。 但是,如果我们使用以下查询: SELECT * FROM words WHERE word LIKE '%A%'; 这将返回包含字母A的任何单词,不管它们是以什么字符开头或结尾的,如"Cake"和"Cat"。 然而,如果我们使用以下查询: SELECT * FROM words WHERE word LIKE '%A'; 这将不起作用,因为LIKE操作符只能以以%结尾的模式进行操作。因此,在这种情况下,索引是无效的,查询将不返回任何结果。 总结而言,LIKE以%开头索引是无效的,因为LIKE操作符只适用于以%结尾的模式匹配。 ### 回答3: "%"开头时,它通常被用作SQL语句中的通配符,用于模糊匹配字符串。在使用"%"作为索引时,由于无法确定具体的开头字符,索引无法有效地帮助优化查询。 当我们在一个大型数据表中执行以"%"开头的like语句时,MySQL无法利用索引来快速定位匹配的行。由于无法使用索引,查询的性能可能受到影响,因为MySQL需要进行全表扫描来找到匹配的行。 然而,在某些情况下,我们仍然可以通过以下方法来改善性能: 1. 使用可以利用索引的其他条件进行筛选。如果查询中有其他条件可以使用索引进行快速定位,那么即使like语句以"%"开头,仍然可以通过其他条件来减少需要扫描的行数。 2. 调整数据库设计。如果我们经常需要在字符串的开头进行模糊匹配,可能需要重新考虑数据库表的结构和索引的设计。例如,可以将需要用作开头匹配的字符串提取出来,作为一个单独的列,并创建一个以该列为前缀的索引。 3. 使用全文索引。在某些情况下,可以考虑使用MySQL的全文索引功能。全文索引可以有效地支持模糊匹配,即使like语句以"%"开头,也可以利用全文索引来加速查询。 总之,当like语句以"%"开头时,索引失效是可能的。对于这种情况,我们可以通过其他条件的利用、调整数据库设计或使用全文索引来提高查询性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值