【MySQL】索引优化与查询优化(重点:索引失效的11种情况)

news2024/10/6 12:32:12

【大家好,我是爱干饭的猿,本文重点介绍MySQL的内连接、外连接、索引失效的11种情况、关联查询优化、子查询优化、排序优化、GROUP BY优化、优化分页查询、覆盖索引、索引条件下推和其它查询优化策略的一些问题。

后续会继续分享MySQL和其他重要知识点总结,如果喜欢这篇文章,点个赞👍,关注一下吧】

上一篇文章:《【MySQL】索引的数据结构(重点:InnoDB中的B+树)》


🤞目录🤞

🍕0. 内连接、外连接区别作用

🍕1. 索引失效案例

1.1 全值匹配

1.2 最佳左前缀法则

1.3 主键插入顺序

1.4 计算、函数、类型转换(自动或手动)导致索引失效

1.5 类型转换导致索引失效

1.6 范围条件右边的列索引失效

1.7 不等于(!= 或者<>)索引失效

1.8 is null可以使用索引,is not null无法使用索引

1.9 like以通配符%开头索引失效

1.10 OR 前后存在非索引的列,索引失效

1.11 数据库和表的字符集统一使用utf8mb4

🍕2. 关联查询优化

🍕3. 子查询优化

🍕4. 排序优化

🍕5. GROUP BY优化

🍕6. 优化分页查询

🍕7. 优先考虑覆盖索引

7.1 什么是覆盖索引?

7.2 覆盖索引的利弊

🍕8. 索引条件下推

8.1 使用前后的扫描过程

🍕9. 其它查询优化策略

9.1 EXISTS 和 IN 的区分

9.2 COUNT(*)与COUNT(具体字段)效率

9.3 关于SELECT(*)

9.4 LIMIT 1 对优化的影响

9.5 多使用COMMIT


🍕0. 内连接、外连接区别作用

不管是内连接、外连接还是带where子句的多表查询,都组合自多个表,并生成结果表。

1. 内连接:只返回两个表中连接字段相等的行。inner join(等值连接) 只返回两个表中联结字段相等的数据

2. 左外连接(也称左连接):返回包括左表中的所有记录和右表中连接字段相等的记录。以左表为基表,在from子句中使用关键字left outer join”或关键字“left join”来连接两张表。

3. 右外连接(也称右连接):返回包括右表中的所有记录和左表中连接字段相等的记录。以右表为基表,在from子句中使用关键字“right outer join”或关键字“right join”来连接两张表。

4. 全外连接:返回左右表中所有的记录和左右表中连接字段相等的记录。在from子句中使用关键字“full outer join”或关键字“full join”来连接两张表。

5.交叉连接(笛卡尔积):返回被连接的两个表所有数据行的笛卡尔积。返回结果集合中的数据行数等于第一个表中复合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。

🍕1. 索引失效案例

MySQL中提高性能的一个最有效的方式是对数据表设计合理的索引。索引提供了访问高效数据的方法,并且加快查询的速度,因此索引对查询的速度有着至关重要的影响。

  • 使用索引可以快速地定位表中的某条记录,从而提高数据库查询的速度,提高数据库的性能。

  • 如果查询时没有使用索引,查询语句就会扫描表中的所有记录。在数据量大的情况下,这样查询的速度会很慢。

大多数情况下都(默认)采用B+树来构建索引。只是空间列类型的索引使用R-树,并且MEMORY表还支持hash索引

其实,用不用索引,最终都是优化器说了算。优化器是基于什么的优化器?基于cost开销(CostBaseOptimizer),它不是基于规则(Rule-BasedOptimizer),也不是基于语义。怎么样开销小就怎么来。另外,SQL语句是否使用索引,跟数据库版本、数据量、数据选择度都有关系。

当Mysql使用索引的要扫描行记录数超过全表的10%-30%时,优化器可能会放弃走索引。
 

1.1 全值匹配

假如有三个索引:

  • 索引1是对一个字段添加了索引
  • 索引2是对二个字段添加了索引
  • 索引3是对三个字段添加了索引

在进行查询中条件判断包含三个字段时,会优先使用索引3,相当于索引1、索引2失效。

1.2 最佳左前缀法则

MySQL可以为多个字段创建索引,一个索引可以包括16个字段。对于多列索引,过滤条件要使用索引必须按照索引建立时的顺序,从左到右,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。如果查询条件中没有使用这些字段中第1个字段时,多列(或联合)索引不会被使用。

1.3 主键插入顺序

对于一个使用InnoDB存储引擎的表来说,在我们没有显示的创建索引时,表中的数据实际上都是存储在聚簇索引的叶子节点的。而记录又存储在数据页中的,数据页和记录又是按照记录主键值从小到大的顺序进行排序,所以如果我们插入的记录的主键值是依次增大的话,那我们每插满一个数据页就换到下一个数据页继续插,而如果我们插入的主键值忽小忽大的话,则可能会造成页面分裂记录移位

1.4 计算、函数、类型转换(自动或手动)导致索引失效

在使用计算、函数、类型转换时,要遍历全表进行计算、函数、类型转换得到一个新的结果和条件值进行比较,所以没有使用索引

1.5 类型转换导致索引失效

如 where name = 111 会类型转换导致索引失效

1.6 范围条件右边的列索引失效

应用开发中范围查询,例如:金额查询,日期查询往往都是范围查询。应将查询条件放置where语句最后。(创建的联合索引中,务必把范围涉及到的字段写在最后)

1.7 不等于(!= 或者<>)索引失效

要进行全表遍历

1.8 is null可以使用索引,is not null无法使用索引

最好在设计数据表的时候就将字段设置为 NOT NULL 约束,比如你可以将INT类型的字段,默认值设置为0。将字符类型的默认值设置为空字符串('')

拓展:同理,在查询中使用not like也无法使用索引,导致全表扫描

1.9 like以通配符%开头索引失效

按照字符串进行匹配,如果%在前就不能按照字符串匹配了。

【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。

1.10 OR 前后存在非索引的列,索引失效

在WHERE子句中,如果在OR前的条件列进行了索引,而在OR后的条件列没有进行索引,那么索引会失效。也就是说,OR前后的两个条件中的列都是索引时,查询中才使用索引。

1.11 数据库和表的字符集统一使用utf8mb4

统一使用utf8mb4( 5.5.3版本以上支持)兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不同的字符集进行比较前需要进行转换会造成索引失效。

例子:若有索引 index(a,b,c)

一般性建议:

  • 对于单列索引,尽量选择针对当前query过滤性更好的索引Ⅰ
  • 在选择组合索引的时候,当前query中过滤性最好的字段在索引字段顺序中,位置越靠前越好
  • 在选择组合索引的时候,尽量选择能够包含当前query中的where子句中更多字段的索引。
  • 在选择组合索引的时候,如果某个字段可能出现范围查询时,尽量把这个字段放在索引次序的最后面。

总之,书写SQL语句时,尽量避免造成索引失效的情况。

🍕2. 关联查询优化

  • 结论1:对于内连接来说,查询优化器可以决定谁来作为驱动表,谁作为被驱动表出现
  • 结论2:对于内连接来讲,如果表的连接条件中只能有一个字段有索引,则有索引的字段所在的表会被作为被驱动表
  • 结论3:对于内连接来说,在两个表的连接条件都存在索引的情况下,会选择小表作为驱动表。小表驱动大表

🍕3. 子查询优化

子查询是 MySQL 的一项重要的功能,可以帮助我们通过一个 SQL 语句实现比较复杂的查询。但是,子查询的执行效率不高。

原因:

① 执行子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表,然后外层查询语句从临时表中查询记录。查询完毕后,再撤销这些临时表。这样会消耗过多的CPU和IO资源,产生大量的慢查询。

② 子查询的结果集存储的临时表,不论是内存临时表还是磁盘临时表都不会存在索引,所以查询性能会受到一定的影响。

③ 对于返回结果集比较大的子查询,其对查询性能的影响也就越大。

在MySQL中,可以使用连接(JOIN)查询来替代子查询。连接查询不需要建立临时表,其速度比子查询要快,如果查询中使用索引的话,性能就会更好。

结论:尽量不要使用NOT IN 或者 NOT EXISTS,用LEFT JOIN xxx ON xx WHERE xx IS NULL替代

🍕4. 排序优化

  1. SQL 中,可以在 WHERE 子句和 ORDER BY 子句中使用索引,目的是在 WHERE 子句中 避免全表扫描,在 ORDER BY 子句避免使用 FileSort 排序。当然,某些情况下全表扫描,或者 FileSort 排序不一定比索引慢。但总的来说,我们还是要避免,以提高查询效率。

  2. 尽量使用 Index 完成 ORDER BY 排序。如果 WHERE 和 ORDER BY 后面是相同的列就使用单索引列;如果不同就使用联合索引。

  3. 无法使用 Index 时,需要对 FileSort 方式进行调优。

🍕5. GROUP BY优化

  • group by 使用索引的原则几乎跟order by一致 ,group by 即使没有过滤条件用到索引,也可以直接使用索引。

  • group by 先排序再分组,遵照索引建的最佳左前缀法则

  • 当无法使用索引列,可以增大max_length_for_sort_datasort_buffer_size参数的设置

  • where效率高于having,能写在where限定的条件就不要写在having中了

  • 减少使用order by,和业务沟通能不排序就不排序,或将排序放到程序端去做。Order by、group by、distinct这些语句较为耗费CPU,数据库的CPU资源是极其宝贵的。

  • 包含了order by、group by、distinct这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢。

🍕6. 优化分页查询

优化思路一

在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容。

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;

🍕7. 优先考虑覆盖索引

7.1 什么是覆盖索引?

理解方式一:索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了满足查询结果的数据就叫做覆盖索引。

理解方式二:非聚簇复合索引的一种形式,它包括在查询里的SELECT、JOIN和WHERE子句用到的所有列(即建索引的字段正好是覆盖查询条件中所涉及的字段)。

简单说就是,索引列+主键包含SELECT 到 FROM之间查询的列

7.2 覆盖索引的利弊

好处:

1. 避免Innodb表进行索引的二次查询(回表)

2. 可以把随机IO变成顺序IO加快查询效率

弊端:

索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这是业务DBA,或者称为业务数据架构师的工作。

🍕8. 索引条件下推

8.1 使用前后的扫描过程

select * from a where key > 'z' and key like '%a'

在不使用ICP索引扫描的过程:

storage层:只将满足index key条件的索引(key>'z')记录对应的整行记录取出,返回给server层,回表

server 层:对返回的数据,使用后面的where条件(key like '%a')过滤,直至返回最后一行。

使用ICP扫描的过程:

storage层:首先将index key条件满足的索引(key>'z')记录区间确定,然后在索引上使用index filter进行(key like '%a')过滤。将满足的index filter条件的索引记录才去回表取出整行记录返回server层。不满足index filter条件的索引记录丢弃,不回表、也不会返回server层。

server 层:对返回的数据,使用table filter条件做最后的过滤。

🍕9. 其它查询优化策略

9.1 EXISTS IN 的区分

索引是个前提,其实选择与否还会要看表的大小。你可以将选择的标准理解为小表驱动大表

9.2 COUNT(*)与COUNT(具体字段)效率

环节1:COUNT(*)COUNT(1)都是对所有结果进行COUNTCOUNT(*)COUNT(1)本质上并没有区别(二者执行时间可能略有差别,不过你还是可以把它俩的执行效率看成是相等的)。如果有WHERE子句,则是对所有符合筛选条件的数据行进行统计;如果没有WHERE子句,则是对数据表的数据行数进行统计。

环节2:如果是MyISAM存储引擎,统计数据表的行数只需要O(1)的复杂度,这是因为每张MyISAM的数据表都有一个meta信息存储了row_count值,而一致性则是由表级锁来保证的。

如果是InnoDB存储引擎,因为InnoDB支持事务,采用行级锁和MVCC机制,所以无法像MyISAM一样,维护一个row_count变量,因此需要采用扫描全表,是O(n)的复杂度,进行循环+计数的方式来完成统计。

环节3:在InnoDB引擎中,如果采用COUNT(具体字段)来统计数据行数,要尽量采用二级索引。因为主键采用的索引是聚簇索引,聚簇索引包含的信息多,明显会大于二级索引(非聚簇索引)。对于COUNT(*)COUNT(1)来说,它们不需要查找具体的行,只是统计行数,系统会自动采用占用空间更小的二级索引来进行统计。

如果有多个二级索引,会使用key_len小的二级索引进行扫描。当没有二级索引的时候,才会采用主键索引来进行统计。

9.3 关于SELECT(*)

在表查询中,建议明确字段,不要使用 * 作为查询的字段列表,推荐使用SELECT <字段列表> 查询。原因:

① MySQL 在解析的过程中,会通过查询数据字典将"*"按序转换成所有列名,这会大大的耗费资源和时间。

② 无法使用覆盖索引

9.4 LIMIT 1 对优化的影响

针对的是会扫描全表的 SQL 语句,如果你可以确定结果集只有一条,那么加上LIMIT 1的时候,当找到一条结果的时候就不会继续扫描了,这样会加快查询速度。

如果数据表已经对字段建立了唯一索引,那么可以通过索引进行查询,不会全表扫描的话,就不需要加上LIMIT 1了。

9.5 多使用COMMIT

只要有可能,在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT 所释放的资源而减少。

COMMIT 所释放的资源:

  • 回滚段上用于恢复数据的信息

  • 被程序语句获得的锁

  • redo / undo log buffer 中的空间

  • 管理上述 3 种资源中的内部花费


分享到此,感谢大家观看!!!

如果你喜欢这篇文章,请点赞关注吧,或者如果你对文章有什么困惑,可以私信我。

🏓🏓🏓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/425951.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot基础学习之(二十一):Swagger基础学习(swagger信息介绍,配置扫描接口和开关,分组和接口注释)

什么是Swagger&#xff1f; Swagger2是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化RESTful 风格的Web 服务 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息。再通过Swagger衍生出来的一系列项目和工具&#xff0c;就可以做到生成各种格式的接口…

Flutter 滚动组件ListView,GridView,Sliver以及滚动监听

前言 身是菩提树 心是明镜台 时时勤拂拭 模式染尘埃 这玩意不难&#xff0c;就是东西多。。。 1 看一下继承关系 class GridView extends BoxScrollView abstract class BoxScrollView extends ScrollView abstract class ScrollView extends StatelessWidget 2 下面是scr…

set和map

set和map关联式容器键值对树状结构关联式容器set介绍使用multiset介绍使用map介绍使用multimap介绍使用底层容器AVL树概念操作节点定义插入旋转红黑树&#xff08;RBTree&#xff09;概念节点的设计迭代器的设计结构插入红黑树模拟实现set与map模拟实现map模拟实现set关联式容器…

【Java 数据结构】单向链表和双向链表的实现 (LinkedList)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

android studio 页面布局(2)

<?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http://schemas.android.com/too…

【数据挖掘与商务智能决策】第九章 随机森林模型

9.1.3 随机森林模型的代码实现 和决策树模型一样&#xff0c;随机森林模型既可以做分类分析&#xff0c;也可以做回归分析。 分别对应的模型为随机森林分类模型&#xff08;RandomForestClassifier&#xff09;及随机森林回归模型&#xff08;RandomForestRegressor&#xff…

Vue.js 2.0 组件

什么是组件&#xff1f; 组件&#xff08;Component&#xff09;是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素&#xff0c;封装可重用的代码。在较高层面上&#xff0c;组件是自定义元素&#xff0c; Vue.js 的编译器为它添加特殊功能。在有些情况下&#xff0c;组件也…

《花雕学AI》19:比较ChatGPT与新Bing在文章润色方面的应用优势与测试案例

引言&#xff1a; 文章润色是指对已经写好的文章进行修改、优化或完善的过程&#xff0c;以提高文章的质量和效果。文章润色涉及到多方面的内容&#xff0c;如语言表达、逻辑结构、文献引用、格式规范等。文章润色对于提升写作水平、提高论文发表率、增加学术影响力等都有重要意…

JavaScript【趣味】做一个网页版2048

文章目录&#x1f31f;前言&#x1f31f;先看效果&#xff08;粉丝特权哈哈&#xff09;&#x1f31f;代码实现&#x1f31f;页面布局 【index.html】&#x1f31f;样式文件【2048.css】&#x1f31f;index.html 里用到的JS文件&#x1f31f;jquery.min.js&#x1f31f;util.js…

300元左右的蓝牙耳机哪个好?300左右音质最好的蓝牙耳机

无线耳机是人们日常生活中必不可少的设备&#xff0c;无论是听音乐化石看电影都能获得身临其境的感觉&#xff0c;由于科技真在发展中&#xff0c;不断地的发生变化&#xff0c;百元价位就可以感受到不错的音色&#xff0c;下面小编整理了几款300左右音质表现不错的蓝牙耳机。 …

Linux 、Android将在汽车舞台上开战

导读在 CES 2017 上&#xff0c;AGL 宣布&#xff0c;Mercedes-Benz 的母公司 Daimler 正式加入。这是第十家汽车制造商加入 AGL&#xff0c;也是第一家德国公司加入 AGL。AGL&#xff08;Automotive Grade Linux&#xff09;&#xff0c;是 Linux 基金会的一个相互协作的开源组…

mallox勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复

目录 前言&#xff1a; 一、mallox勒索病毒及xollam勒索病毒的特点 二、mallox勒索病毒及xollam勒索病毒的影响 三、mallox勒索病毒及xollam勒索病毒数据恢复服务 四、mallox勒索病毒及xollam勒索病毒加密数据库恢复案例 五、以下是预防mallox勒索病毒及xollam勒索病毒安全…

解读CANDT测试项-采样点测试

原标题&#xff1a;解读CANDT测试项-采样点测试 一、为什么要进行采样点测试&#xff1f; 本文引用地址&#xff1a;http://www.eepw.com.cn/article/202004/411611.htm 为了保证有效的通信&#xff0c;对于一个只有两个节点的CAN网络&#xff0c;其两边距离不超过最大的传输…

day12 共享内存(内存映射的使用、注意事项、进程间通信、systemV共享内存)

内存映射的基本使用 概念&#xff1a; 功能共享内存可以通过mmap&#xff08;&#xff09;映射普通文件。 是一个磁盘文件与内存中的一个缓冲区相映射&#xff0c;进程可以像访问普通内存一样对文件进行访问&#xff0c;不必在调用read 、write。 mmap&#xff08;&#xf…

ChatGPT 与 MindShow 一分钟搞定一个PPT

前言 PPT制作是商务、教育和各种场合演讲的重要组成部分。然而&#xff0c;很多人会花费大量时间和精力在内容生成和视觉设计方面。为了解决这个问题&#xff0c;我们可以利用两个强大的工具——ChatGPT和MindShow&#xff0c;来提高制作PPT的效率。 一、ChatGPT 与 MindShow…

JUC-01 线程的创建和状态转换

本次我们主要讲三个问题 线程是什么&#xff1f;线程有哪些状态&#xff1f;各状态间的转换了解吗&#xff1f;创建线程的3种方法你都了解吗&#xff1f; 1. 线程是什么&#xff1f;&#xff08;了解即可&#xff09; 进程&#xff1a; 进程是一个具有一定独立功能的程序在一…

四次挥手刨根问底19问详解,全网最全

1.请描述一下TCP连接的四次挥手过程&#xff1f; 回答&#xff1a;TCP连接的四次挥手过程包括以下步骤&#xff1a; 步骤1&#xff1a;客户端向服务器端发送一个FIN报文段&#xff0c;请求关闭连接。 步骤2&#xff1a;服务器端收到FIN报文段后&#xff0c;向客户端发送一个…

python列表,元组和字典

1、python列表 1.1.列表的定义 list是一种有序的集合、基于 链表实现,name[ ] ,全局定义:list2list([ ])。 1.2下标索引 python不仅有负索引也有正索引。正索引从0开始,负索引从-1开始。这两个可以混用,但指向还是那个位置 a[0]a[-9]//length为10的数组a1.3列表的切片 列表可…

navicat如何使用orcale(详细步骤)

目录前言操作1.连接数据库2.建库问题总结前言 看过我昨天文章的兄弟姐妹都知道最近接手另一个国企项目&#xff0c;数据库用的是orcale。实话实说&#xff0c;也有快三年没用过orcale数据库了。 这期间问题不断&#xff0c;因为orcale日渐消沉&#xff0c;网上资料也是真真假…

UE4 回放系统升级到UE5之后的代码报错问题解决

关键词&#xff1a; UE4 回放系统 升级 UE5 报错 DemoNetDriver GetDemoCurrentTime GetDemoTotalTime 背景 照着网上教的UE4的回放系统&#xff0c;也叫重播系统&#xff0c;英文Replay。做完了&#xff0c;测试运行正常&#xff0c;可升级到UE5却报了一堆 WorldSetting 和 …