几个必须掌握的SQL优化技巧(七):索引的最佳使用法则

简介: 在应用的开发过程中,由于开发初期的数据量一般都比较小,所以开发过程中一般都比较注重功能上的实现,但是当完成了一个应用或者系统之后,随着生产数据量的急剧增长,那么之前的很多sql语句的写法就会显现出一定的性能问题,对生产的影响也会越来越大,这些不恰当的sql语句就会成为整个系统性能的瓶颈,为了追求系统的极致性能,必须要对它们进行优化。

1 前言


在应用的开发过程中,由于开发初期的数据量一般都比较小,所以开发过程中一般都比较注重功能上的实现,但是当完成了一个应用或者系统之后,随着生产数据量的急剧增长,那么之前的很多sql语句的写法就会显现出一定的性能问题,对生产的影响也会越来越大,这些不恰当的sql语句就会成为整个系统性能的瓶颈,为了追求系统的极致性能,必须要对它们进行优化。


2 正文


前面一篇文章几个必须掌握的SQL优化技巧(六):针对SQL语句的优化介绍了数据库优化中关于sql语句的几种优化方式,索引也是数据库优化中最重要也是最高效的手段之一,通过索引通常可以帮助用户解决大多数mysql的性能优化问题。这篇文章就来介绍如何对索引进行优化。


首先我们来看看索引对查询效率是否有提升以及提升效果如何。


在tb_item表中有300万条数据:


7f7678065d5845c79c3b73f9add5af83~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp (1).jpg


在tb_item表中id是主键索引,通过id作为查询条件可以看到查询速度很快,基本没有查询时间:


f194220166674b2fbfe7b31fae8fd04a~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


而如果将title非索引字段作为查询条件可以看到,查询时间是比较慢的:


6c147754444d480cae8c209187982086~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


在对title字段也创建索引之后,查询效率明显提升了,所以索引的使用对于数据的查询性能具有很明显的提升。


3aaa6918261e4d8cac9946e250a96957~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


但是并非只要创建了索引就能够提升查询效率,只有创建了索引并且合理利用了索引对查询效率才能有明显的提升。


在索引的使用中需要注意以下几点:


1、全值匹配,对索引中所有列都指定具体的值


比如 user表中name、code和email都是索引,那么在查询中如果给这三个索引都指定查询的值,那么执行效率比较高:


select * from user where name='张三' and code='1001' and email='123456@163.com'
复制代码


2、最左前缀法则


如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最左前列开始,并且不跳过索引中的列,比如user表中创建了复合索引:


create index idx_user_name_code_email on user(name,code,email)
复制代码


那么最左前缀法则值得就是索引从最左边的name开始并且不能跳过code直接到email。


比如,下面这三句sql就是符合最左前缀法则的


select * from user where name='张三' 
select * from user where name='张三' and code='1001' 
select * from user where name='张三' and code='1001' and email='123456@163.com'
复制代码


但是下面的就不符合最左前缀法则了:


select * from user where code='1001' and email='123456@163.com'
select * from user where email='123456@163.com'
select * from user where name='张三' and email='123456@163.com'
复制代码


不符合最左前缀法则的sql语句就会导致索引失效。


但是下面这句是复合最左前缀法则:


select * from user where code='1001' and email='123456@163.com' and name='张三'
复制代码


另外对于:


select * from user where name='张三' and email='123456@163.com
复制代码


上面这条sql其实也会走索引,但是只会走name索引,而email索引会失效。


所以最左前缀法则值得是后面的where条件包不包含最左边的索引字段,而与where条件后面索引的顺序无关的,如果where条件后面包含最左列索引,并且没有跳过其他索引,那么会走索引,否则会使索引失效。这就好比闯关游戏,闯关需要从第一关到最后一关按照顺序来闯关,不能跳过第一关直接到第二关,也不能第一关闯完,直接跳过第二关来到第三关。


3、范围查询右边的列,索引会失效


指的是在复合索引中,如果某个索引使用了范围查询,那么这个索引后面的索引会失效,比如:


select * from user where name='张三' and code>'1001' and email='123456@163.com'
复制代码


上面这条语句只有name和code索引生效,但是email索引会失效了。


4、在索引列上进行函数运算操作,索引会失效


比如:


select * from user where substring(name,0,2) = '张三' 
复制代码


上面这样的sql语句,会使得name索引失效。


5、字符串不加单引号,索引会失效


比如:


select * from user where name='张三' and code=1001
复制代码


上面的语句虽然能查询数据,但是其实后面的code并没有走到索引,索引只有name,因为表中code是varchar类型的,但是这里是int类型,所以在查询的时候,sql在执行的时候对code进行了隐式转换转换为varchar,其实就等同于第四点在索引列上进行函数运算操作,导致了索引会失效。


6、尽量使用覆盖索引,避免使用 *


在进行查询的时候尽量使用覆盖索引即只访问索引的查询(索引列完全包含查询列),而尽量不要使用select * 进行查询,如果查询列的字段超出了索引列,也会降低性能。比如name,code,email三个字段是索引字段,那么


select * from user where name='张三'
select name,code,email,password from user where name='张三'
复制代码



select name,code,email from user where name='张三'
复制代码


的查询效率都低。因为select *和查询字段超过了索引字段的查询中,虽然用到了索引,但是需要进行回表查询数据。即先查询索引的字段信息,但是并不是包含所有的数据信息,而是根据查询索引字段的信息从而获取该一行所有的数据。


7、关于like模糊查询


在使用like进行模糊查询的时候,如果以%开头的like进行模糊查询,那么会导致索引失效,而如果仅仅是%在尾部进行模糊匹配,索引不会失效。比如


select * from user where name='%张三'
select * from user where name='%张三%'
复制代码


会导致索引失效,而

select * from user where name='张三%'
复制代码


的索引还是会有用。所以进行模糊匹配尽量匹配的值头部不要加%。但是可以通过覆盖索引来使得这种情况的索引生效。比如


select id,name,code,email from user where name='%张三'
复制代码


这种情况下,索引还是会生效的。


8、关于or的使用


在用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到,比如如果name是索引列,而password字段不是索引列,那么中间是用or进行条件连接是不走索引的,索引失效


select * from user where name='张三' or password='123456'
复制代码


如果中间使用and,那么还是会用到索引:


select * from user where name='张三' and password='123456'
复制代码


9、关于is null 和 is not null的使用


在对于索引字段使用is null 或者is not null 作为条件查询的时候,有时候会走索引,有时候会使索引失效,比如user表中的name字段没有空值,那么如果


select * from user where name is null 
复制代码


这时候name字段的值是没有null或者null值是比较少的,底层在进行评估的的时候会走索引;而如果条件是 is not null,因为该字段的值都是is not null或者绝大部分值是is not null,那么索引就会失效,这时候会走全表扫描的查询速度会更快。is null 和is not null,反过来也是同样的。


10、关于in和 not in的使用


使用in会走索引,而使用not in索引会失效。


走索引:


select * from user where name in ('张三','张四','张五')
复制代码


索引失效:


select * from user where name not in ('张三','张四','张五')
复制代码


11、关于单列索引和复合索引的选择


在创建sql语句的时候,尽量使用复合索引,而少使用单列索引。


因为,比如在创建一个复合索引的时候:


create index idx_user_name_code_email on user(name,code,email)
复制代码


其实相当于创建了三个索引:name、name+code、name+code+email;


而创建三个单列索引:


create index idx_user_name on user(name)
create index idx_user_code on user(code)
create index idx_user_email on user(email)
复制代码


这时候如果在对这三个索引字段进行查询的时候,可能使用到的索引是上面三个单列索引,但是实际上数据库底层评估会根据字段的数据的辨识度选择一个最优的索引来使用,而不会使用全部的索引。


对于复合索引的话,里面的字段也不是越多就越好,索引包含过多的字段,会导致索引臃肿庞大,维护的开销也会因此增大,所以如果用于筛选的字段有很多,那么我们就要选出最大价值的筛选字段来作为复合索引的一份子。比如A字段的数据重复率低,B字段的数据重复率高,那么A就比B更有资格参与复合索引的建设,同时为了避免索引维护开销过大,建议非唯一索引中包含的字段不要超过5个,那么正常情况下,需要优先选择辨识度高的那5个字段,从高到低排列。


最后可以通过以下的命令来查看索引的使用情况:


-- 查看当前会话的索引使用情况
show status like 'Handler_read%'
-- 查看全局的索引使用情况
show global status like 'Handler_read%'
复制代码


a7ced3c5ec5d4fc085bbf17371f11c8a~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


在这里会涉及到几个参数指标:


Handler_read_fist:索引中第一条被读的次数,如果较高,表示服务器正执行大量索引扫描,这个值越低越好;


Handler_read_key:如果索引正在工作,这个值代表一个行被索引值读的次数,如果这个值越低,表示索引得到的性能改善不高,因为索引不经常被使用,所以这个值越高越好;


Handler_read_next:按照键顺序读下一行的请求数,如果你用范围约束或如果执行索引扫描来查询索引列会导致该值增加;

Handler_read_prev:按照键顺序读前一行的请求数。该读方法主要用于优化 order by desc;


Handler_read_rnd:根据固定位置读一行的请求数,如果你正执行大量查询并需要对结果进行排序该值较高,则可能使用了大量需要mysql扫描整个表的查询或连接没有正确使用键,这个值较高,意味着运行效率较低,应该建立索引来优化;


Handler_read_rnd_next:在数据文件中读下一行的请求数,如果你正进行大量的表扫描,该值较高。通常说明你的表索引不正确或者写入的查询并没有利用索引。


该方法对于索引优化可以起到一个参考的作用。


3 总结


上面就是在数据库优化中关于索引的使用和优化的全部内容,这里只是总结了工作中了解到的一些关于索引优化的原则,还有一些其他的优化办法需要我们在日常的工作和学习中,不断的总结和积累。


至此,关于SQL优化技巧系列的文章已经全部写完了,后面也还会写一些其他关于数据库相关的文章。


最后如果觉得本文写得不错,就推荐给更多的人呗。

目录
相关文章
|
4月前
|
SQL 存储 关系型数据库
如何巧用索引优化SQL语句性能?
本文从索引角度探讨了如何优化MySQL中的SQL语句性能。首先介绍了如何通过查看执行时间和执行计划定位慢SQL,并详细解析了EXPLAIN命令的各个字段含义。接着讲解了索引优化的关键点,包括聚簇索引、索引覆盖、联合索引及最左前缀原则等。最后,通过具体示例展示了索引如何提升查询速度,并提供了三层B+树的存储容量计算方法。通过这些技巧,可以帮助开发者有效提升数据库查询效率。
401 2
|
5月前
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
794 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
4月前
|
SQL Oracle 关系型数据库
SQL优化-使用联合索引和函数索引
在一次例行巡检中,发现一条使用 `to_char` 函数将日期转换为字符串的 SQL 语句 CPU 利用率很高。为了优化该语句,首先分析了 where 条件中各列的选择性,并创建了不同类型的索引,包括普通索引、函数索引和虚拟列索引。通过对比不同索引的执行计划,最终确定了使用复合索引(包含函数表达式)能够显著降低查询成本,提高执行效率。
|
4月前
|
SQL 关系型数据库 MySQL
如何确认SQL用了索引:详细技巧与方法
在数据库管理中,索引是提高SQL查询性能的重要手段
|
5月前
|
存储 关系型数据库 MySQL
MySQL高级篇——覆盖索引、前缀索引、索引下推、SQL优化、主键设计
覆盖索引、前缀索引、索引下推、SQL优化、EXISTS 和 IN 的区分、建议COUNT(*)或COUNT(1)、建议SELECT(字段)而不是SELECT(*)、LIMIT 1 对优化的影响、多使用COMMIT、主键设计、自增主键的缺点、淘宝订单号的主键设计、MySQL 8.0改造UUID为有序
|
5月前
|
SQL 存储 索引
SQL Server的Descending Indexes降序索引
【9月更文挑战第21天】在SQL Server中,降序索引允许指定列的排序顺序为降序,可显著优化涉及降序排序的查询性能,特别是在复合索引中。通过创建降序索引,可以更高效地满足特定业务需求,如按交易时间降序获取最新记录。然而,使用时需考虑查询频率、数据分布及维护成本,以确保最佳性能。
|
4月前
|
SQL 存储 关系型数据库
SQL默认索引是什么:深入解析与技巧
在SQL数据库中,索引是一种用于提高查询性能的重要数据结构
|
4月前
|
SQL 存储 关系型数据库
SQL默认索引是什么
在SQL数据库中,索引是一种用于提高查询性能的数据结构
|
4月前
|
SQL 关系型数据库 MySQL
如何确认SQL用了索引
在数据库管理和优化过程中,确认SQL查询是否使用了索引是一个至关重要的步骤
|
4月前
|
SQL 关系型数据库 MySQL
如何确认SQL查询是否使用了索引:详细步骤与技巧
在数据库管理和优化中,确认SQL查询是否有效利用了索引是提升性能的关键步骤