索引失效
1.没有符合最左前缀原则 2.字段进行了隐式数据类型转换 3.走索引没有全表扫描效率高
联合索引不满足最左匹配原则
联合索引遵从最左匹配原则,顾名思义,在联合索引中,最左侧的字段优先匹配。因此,在创建联合索引时,where子句中使用最频繁的字段放在组合索引的最左侧。
使用了select *
阿里巴巴java开发手册
【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。
说明:1)增加查询分析器解析成本。
2)增减字段容易与 resultMap 配置不一致。
3)无用字段增加网络 消耗,尤其是 text 类型的字段。
禁止使用select * 语句可能会带来的附带好处就是:某些情况下可以走覆盖索引。
索引列参与运算
导致全表扫描,索引失效
select * from t_user where id + 1 = 2 ;
索引列参使用了函数
explain select * from t_user where SUBSTR(id_no,1,3) = '100';
like以通配符%开头索引失效
拓展:Alibaba《Java开发手册》
【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。
类型转换导致索引失效
id_no 是 varchar类型,这么传参就发生了类型转换,导致索引失效
explain select * from t_user where id_no = 1004;
or
前后存在非索引的列,索引失效
查询条件使用or关键字,其中一个字段没有创建索引,则会导致整个查询语句索引失效; or两边为“>”和“<”范围查询时,索引失效。
不等于(!= 或者<>)索引失效
is null可以使用索引,is not null无法使用索引
数据库和表的字符集统一使用utf8mb4
统一使用utf8mb4( 5.5.3版本以上支持)兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不
同的 字符集 进行比较前需要进行 转换 会造成索引失效。
索引优化
关联查询优化
join语句原理
EXPLAIN SELECT * FROM t1 STRAIGHT_JOIN t2 ON (t1.a=t2.a)
如果直接使用join语句,MySQL优化器可能会选择表t1或t2作为驱动表,这样会影响我们分析SQL语句的执行过程。所以,为了便于分析执行过程中的性能问题,我改用 straight_join
让 MySQL
使用固定的连接方式执行查询,这样优化器只会按照我们指定的方式去join。在这个语句里,t1 是驱动表,t2是被驱动表。
- 从表t1中读入一行数据 R;
- 从数据行R中,取出a字段到表t2里去查找;
- 取出表t2中满足条件的行,跟R组成一行,作为结果集的一部分;
- 重复执行步骤1到3,直到表t1的末尾循环结束。
这个过程是先遍历表t1,然后根据从表t1中取出的每行数据中的a值,去表t2中查找满足条件的记录。在
形式上,这个过程就跟我们写程序时的嵌套查询类似,并且可以用上被驱动表的索引,所以我们称之为
“Index Nested-Loop Join”
,简称NLJ。
下面这张图的前提是 join的字段有索引哦!!!!
在这个流程里:
1. 对驱动表t1做了全表扫描,这个过程需要扫描100行;
- 而对于每一行R,根据a字段去表t2查找,走的是树搜索过程。由于我们构造的数据都是一一对应的,因此每次的搜索过程都只扫描一行,也是总共扫描100行;
-
所以,整个执行流程,总扫描行数是200。
总结
-
保证被驱动表的JOIN字段已经创建了索引
-
需要JOIN 的字段,数据类型保持绝对一致。
-
LEFT JOIN 时,选择小表作为驱动表, 大表作为被驱动表 。减少外层循环的次数。
-
INNER JOIN 时,MySQL会自动将 小结果集的表选为驱动表 。选择相信MySQL优化策略。
-
能够直接多表关联的尽量直接关联,不用子查询。(减少查询的趟数)
-
不建议使用子查询,建议将子查询SQL拆开结合程序多次查询,或使用 JOIN 来代替子查询。
子查询优化
子查询是 MySQL 的一项重要的功能,可以帮助我们通过一个 SQL 语句实现比较复杂的查询。但是,子查询的执行效率不高。原因:
- ① 执行子查询时,
MySQL
需要为内层查询语句的查询结果 建立一个临时表 ,然后外层查询语句从临时表中查询记录。查询完毕后,再 撤销这些临时表 。这样会消耗过多的CPU和IO
资源,产生大量的慢查询。 -
② 子查询的结果集存储的临时表,不论是内存临时表还是磁盘临时表都 不会存在索引 ,所以查询性能会受到一定的影响。
-
③ 对于返回结果集比较大的子查询,其对查询性能的影响也就越大。
1.在MySQL中,可以使用连接(JOIN)查询来替代子查询。连接查询 不需要建立临时表 ,其 速度比子查询要快 ,如果查询中使用索引的话,性能就会更好。
2.在MySQL中,可以使用连接(JOIN)查询来替代子查询。连接查询 不需要建立临时表 ,其 速度比子查询要快 ,如果查询中使用索引的话,性能就会更好。
排序优化
-
- SQL 中,可以在 WHERE 子句和 ORDER BY 子句中使用索引,目的是在 WHERE 子句中 避免全表扫描 ,在 ORDER BY 子句 避免使用 FileSort 排序 。当然,某些情况下全表扫描,或者 FileSort 排序不一定比索引慢。但总的来说,我们还是要避免,以提高查询效率。
-
- 尽量使用 Index 完成 ORDER BY 排序。如果 WHERE 和 ORDER BY 后面是相同的列就使用单索引列;如果不同就使用联合索引。
-
- 无法使用 Index 时,需要对 FileSort 方式进行调优。
group By 优化
group by
使用索引的原则几乎跟order by一致 ,group by 即使没有过滤条件用到索引,也可以直接使用索引。-
group by
先排序再分组,遵照索引建的最佳左前缀法则当无法使用索引列,增大max_length_for_sort_data 和 sort_buffer_size
参数的设置 -
where
效率高于having
,能写在where
限定的条件就不要写在having
中了 -
减少使用
order by
,和业务沟通能不排序就不排序,或将排序放到程序端去做。Order by、group by、distinct
这些语句较为耗费CPU
,数据库的CPU
资源是极其宝贵的。 -
包含了
order by、group by、distinct
这些查询的语句,where
条件过滤出来的结果集请保持在1000
行以内,否则SQL
会很慢。
分页查询优化
- 在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容。
EXPLAIN SELECT * FROM student t,(SELECT id FROM student ORDER BY id LIMIT 2000000,10)
a
WHERE t.id = a.id;
- 于主键自增的表,可以把Limit 查询转换成某个位置的查询 。
EXPLAIN SELECT * FROM student WHERE id > 2000000 LIMIT 10
字符串加索引
说使用前缀索引,定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本。上一篇文章 《Mysql索引 二》已经讲过区分度,区分度越高越好。因为区分度越高,意味着重复的键值越少。
前缀索引对覆盖索引的影响
使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是你在选择是否使用前缀索引时需要考虑的一个因素。
其他优化策略
EXISTS 和 IN 的区分
COUNT(*)与COUNT(具体字段)
效率
关于SELECT(*)
在表查询中,建议明确字段,不要使用 * 作为查询的字段列表,推荐使用SELECT <字段列表> 查询。原因:
① MySQL 在解析的过程中,会通过 查询数据字典 将”*”按序转换成所有列名,这会大大的耗费资源和时间。
② 无法使用 覆盖索引
LIMIT 1
对优化的影响
针对的是会扫描全表的 SQL
语句,如果你可以确定结果集只有一条,那么加上 LIMIT 1
的时候,当找到一条结果的时候就不会继续扫描了,这样会加快查询速度。
如果数据表已经对字段建立了唯一索引,那么可以通过索引进行查询,不会全表扫描的话,就不需要加上 LIMIT 1
了。
多使用COMMIT
只要有可能,在程序中尽量多使用COMMIT
,这样程序的性能得到提高,需求也会因为COMMIT
所释放的资源而减少。
– COMMIT
所释放的资源:
– 回滚段上用于恢复数据的信息
- 被程序语句获得的锁
- `redo / undo log buffer` 中的空间
- 管理上述 3 种资源中的内部花费
索引下推
MySQL 5.6中新特性,是一种在存储引擎层使用索引过滤数据的一种优
化方式。ICP可以减少存储引擎访问基表的次数以及MySQL服务器访问存储引擎的次数。
ICP的使用条件:
– ① 只能用于二级索引(secondary index)
- ②explain显示的执行计划中type值(join 类型)为
range 、 ref 、 eq_ref 或者 ref_or_null
。 -
③ 并非全部
where
条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where
过滤。 -
④ ICP可以用于
MyISAM和InnnoDB
存储引擎 -
⑤
MySQL 5.6
版本的不支持分区表的ICP
功能,5.7版本的开始支持。 -
⑥ 当SQL使用覆盖索引时,不支持
ICP
优化方法
覆盖索引
理解方式一:索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了满足查询结果的数据就叫做覆盖索引。
理解方式二:非聚簇复合索引的一种形式,它包括在查询里的SELECT、JOIN和WHERE子句用到的所有列(即建索引的字段正好是覆盖查询条件中所涉及的字段)。
简单说就是, 索引列+主键 包含 SELECT 到 FROM
之间查询的列 。
好处:
– 1. 避免Innodb
表进行索引的二次查询(回表)
-
- 可以把随机
IO
变成顺序IO
加快查询效率
- 可以把随机
弊端:
索引字段的维护 总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这是业务DBA
,或者称为业务数据架构师的工作。
思考
普通索引 唯一索引区别
假设,执行查询的语句是 select id from test where k=5。
- 对于普通索引来说,查找到满足条件的第一个记录(5,500)后,需要查找下一个记录,直到碰到第一个不满足k=5条件的记录。
-
对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。
那么,这个不同带来的性能差距会有多少呢?答案是, 微乎其微 。
参考文献
文章部分内容引用自宋红康老师的Mysql高级课程,在此表示感谢,如有侵权,请联系站长进行删除
<声明>:
谁都不是生下来就会的,都不是三体人,知识也可以遗传,我们的东西都是学习到的,所以每个人的知识体系难免有老师的身影,先学习后模仿,才能学会,至于笔记,摘抄部分我感觉难免,学会了就是自己的!