索引法则--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以%开头会导致索引失效;使用覆盖索引解决之
索引法则--LIKE以%开头会导致索引失效进而转向全表扫描(使用覆盖索引解决)的更多相关文章
- 陷阱~SQL全表扫描与聚集索引扫描
		SqlServer中在查询时,我们为了优化性能,通常会为where条件的字段建立索引,如果条件比较固定还会建立组合索引,接下来,我们来看一下索引与查询的相关知识及相关陷阱. SQL表自动为主键加聚集索 ... 
- SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析
		在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index ... 
- SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析 (转载)
		在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index ... 
- SQL  数据优化索引建suo避免全表扫描
		首先什么是全表扫描和索引扫描?全表扫描所有数据过一遍才能显示数据结果,索引扫描就是索引,只需要扫描一部分数据就可以得到结果.如果数据没建立索引. 无索引的情况下搜索数据的速度和占用内存就会比用索引的检 ... 
- sql语句优化:尽量使用索引避免全表扫描
		1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ... 
- 【翻译自mos文章】SYS_OP_C2C 导致的全表扫描(fts)/全索引扫描
		SYS_OP_C2C 导致的全表扫描(fts)/全索引扫描 參考原文: SYS_OP_C2C Causing Full Table/Index Scans (Doc ID 732666.1) 适用于: ... 
- 如何优雅的使用 参数 is null而不导致全表扫描(破坏索引)
		相信大家在很多实际业务中(特别是后台系统)会使用到各种筛选条件来筛选结果集 首先添加测试数据 ), Age INT) go CREATE INDEX idx_age ON TempList (Age) ... 
- mysql不会使用索引,导致全表扫描情况
		不会使用索引,导致全表扫描情况 1.不要使用in操作符,这样数据库会进行全表扫描,推荐方案:在业务密集的SQL当中尽量不采用IN操作符 2.not in 使用not in也不会走索引推荐方案:用not ... 
- MYSQL的全表扫描,主键索引(聚集索引、第一索引),非主键索引(非聚集索引、第二索引),覆盖索引四种不同查询的分析
		文章出处:http://inter12.iteye.com/blog/1430144 MYSQL的全表扫描,主键索引(聚集索引.第一索引),非主键索引(非聚集索引.第二索引),覆盖索引四种不同查询的分 ... 
随机推荐
- Python内置函数(4)——min
			英文文档: min(iterable, *[, key, default]) min(arg1, arg2, *args[, key]) Return the smallest item in an ... 
- ssh整合之一spring的单独运行环境
			这是本人第一次写博客,不足之处,还希望各位园友指出,在此先谢谢各位了! 先说我们的这三大框架,即struts,spring,hibernate,我们要进行整合的话,第一步是先单独搭建我们的Spring ... 
- Python之线程
			操作系统线程理论 线程概念的引入背景 进程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别 ... 
- git 添加管理成员
			git 添加管理成员 登录git后的样子: 具体操作流程看截图和说明 : * 图中1:打开设置面板: * 图中2:打开成员面板: * 图中3:添加成员功能标签: * 图中4:添加的成员,这里会弹出 ... 
- 南京邮电大学java程序设计作业在线编程第二次作业
			王利国的"Java语言程序设计第2次作业(2018)"详细 作业结果详细 总分:100 选择题得分:60 1. 表达式9==8&&3<7的运算结果是( ) ... 
- Spring学习之AOP与事务
			一.概述 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续, ... 
- 使用 WTForms 进行表单验证的例子
			#使用 WTForms 进行表单验证的例子 from wtforms import Form from wtforms import BooleanField from wtforms import ... 
- PhantomJS命令行选项
			支持命令行选项有: --help或-h列出所有可能的命令行选项.立即停止,不会运行一个脚本作为参数传递. --version或-v打印的版本PhantomJS.立即停止,不会运行一个脚本作为参数传递. ... 
- springboot--mybatis--pagehelper分页整合不起作用
			今天配置pagehelper,在pom文件中都使用的最新版本jar包,步骤都没问题,之后才发现是包的问题. 有问题:分页配置不起作用 <dependency> <groupId> ... 
- ES6(正则扩展)
			ES6中正则的扩展 正则新增特性 一.构造函数的变化 1.ES5中new一个正则对象方法 (一行中2个参数,二行中1个参数) (第一行中的第一个参数必须是字符串) 2.ES6中新增一种方法(构造函数) ... 
