不要一把梭了,这才是SQL优化的正确姿势!|原创干货

这是我的第 83 篇原创文章

作者 | 王磊

来源 | Java中文社群(ID:javacn666)

转载请联系授权(微信ID:GG_Stone)

年少不知优化苦,遇坑方知优化难。——村口王大爷

全文内容预览:


我之前有很多文章都在讲性能优化的问题,比如下面这些:

  1. 《switch 的性能提升了 3 倍,我只用了这一招!》

  2. 《String性能提升10倍的几个方法!(源码+原理分析)》

  3. 《局部变量竟然比全局变量快 5 倍?》

  4. 《池化技术到达有多牛?看了线程和线程池的对比吓我一跳!》

  5. 《链表竟然比数组慢了1000多倍?(动图+性能评测)》

  6. 《HashMap 的 7 种遍历方式与性能分析!》

  7. 更多性能优化文章

当然,本篇也是关于性能优化的,那性能优化就应该一把梭子吗?还是要符合一些规范和原则呢?

所以,在开始之前(MySQL 优化),咱们先来聊聊性能优化的一些原则。

性能优化原则和分类

性能优化一般可以分为:

  • 主动优化

  • 被动优化

所谓的主动优化是指不需要外力的推动而自发进行的一种行为,比如当服务没有明显的卡顿、宕机或者硬件指标异常的情况下,自我出发去优化的行为,就可以称之为主动优化。


而被动优化刚好与主动优化相反,它是指在发现了服务器卡顿、服务异常或者物理指标异常的情况下,才去优化的这种行为。

性能优化原则

无论是主动优化还是被动优化都要符合以下性能优化的原则:

  1. 优化不能改变服务运行的逻辑,要保证服务的正确性

  2. 优化的过程和结果都要保证服务的安全性

  3. 要保证服务的稳定性,不能为了追求性能牺牲程序的稳定性。比如不能为了提高 Redis 的运行速度,而关闭持久化的功能,因为这样在 Redis 服务器重启或者掉电之后会丢失存储的数据。

以上原则看似都是些废话,但却给了我们一个启发,那就是我们性能优化手段应该是:预防性能问题为主+被动优化为辅

也就是说,我们应该以预防性能问题为主,在开发阶段尽可能的规避性能问题,而在正常情况下,应尽量避免主动优化,以防止未知的风险(除非是为了 KPI,或者是闲的没事),尤其对生产环境而言更是如此,最后才是考虑被动优化

PS:当遇到性能缓慢下降、或硬件指标缓慢增加的情况,如今天内存的占用率是 50%,明天是 70%,后天是 90% ,并且丝毫没有收回的迹象时,我们应该提早发现并处理此类问题(这种情况也属于被动优化的一种)。

MySQL 被动性能优化

所以我们本文会重点介绍 MySQL 被动性能优化的知识,根据被动性能优化的知识,你就可以得到预防性能问题发生的一些方法,从而规避 MySQL 的性能问题

本文我们会从问题入手,然后考虑这个问题产生的原因以及相应的优化方案。我们在实际开发中,通常会遇到以下 3 个问题:

  1. 单条 SQL 运行慢;

  2. 部分 SQL 运行慢;

  3. 整个 SQL 运行慢。


问题 1:单条 SQL 运行慢

问题分析

造成单条 SQL 运行比较慢的常见原因有以下两个:

  1. 未正常创建或使用索引;

  2. 表中数据量太大。

解决方案 1:创建并正确使用索引

索引是一种能帮助 MySQL 提高查询效率的主要手段,因此一般情况下我们遇到的单条 SQL 性能问题,通常都是由于未创建或为正确使用索引而导致的,所以在遇到单条 SQL 运行比较慢的情况下,你首先要做的就是检查此表的索引是否正常创建

如果表的索引已经创建了,接下来就要检查一下此 SQL 语句是否正常触发了索引查询,如果发生以下情况那么 MySQL 将不能正常的使用索引:

  1. 在 where 子句中使用 != 或者 <> 操作符,查询引用会放弃索引而进行全表扫描;

  2. 不能使用前导模糊查询,也就是 '%XX' 或 '%XX%',由于前导模糊不能利用索引的顺序,必须一个个去找,看是否满足条件,这样会导致全索引扫描或者全表扫描;

  3. 如果条件中有 or 即使其中有条件带索引也不会正常使用索引,要想使用 or 又想让索引生效,只能将 or 条件中的每个列都加上索引才能正常使用;

  4. 在 where 子句中对字段进行表达式操作。

因此你要尽量避免以上情况,除了正常使用索引之外,我们也可以使用以下技巧来优化索引的查询速度

  1. 尽量使用主键查询,而非其他索引,因为主键查询不会触发回表查询;

  2. 查询语句尽可能简单,大语句拆小语句,减少锁时间;

  3. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型;

  4. 用 exists 替代 in 查询;

  5. 避免在索引列上使用 is null 和 is not null。

回表查询:普通索引查询到主键索引后,回到主键索引树搜索的过程,我们称为回表查询。

解决方案 2:数据拆分

当表中数据量太大时 SQL 的查询会比较慢,你可以考虑拆分表,让每张表的数据量变小,从而提高查询效率。

1.垂直拆分

指的是将表进行拆分,把一张列比较多的表拆分为多张表。比如,用户表中一些字段经常被访问,将这些字段放在一张表中,另外一些不常用的字段放在另一张表中,插入数据时,使用事务确保两张表的数据一致性。垂直拆分的原则:

  • 把不常用的字段单独放在一张表;

  • 把 text,blob 等大字段拆分出来放在附表中;

  • 经常组合查询的列放在一张表中。

2.水平拆分

指的是将数据表行进行拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。通常情况下,我们使用取模的方式来进行表的拆分,比如,一张有 400W 的用户表 users,为提高其查询效率我们把其分成 4 张表 users1,users2,users3,users4,然后通过用户 ID 取模的方法,同时查询、更新、删除也是通过取模的方法来操作。

表的其他优化方案:
  1. 使用可以存下数据最小的数据类型;

  2. 使用简单的数据类型,int 要比 varchar 类型在 MySQL 处理简单;

  3. 尽量使用 tinyint、smallint、mediumint 作为整数类型而非 int;

  4. 尽可能使用 not null 定义字段,因为 null 占用 4 字节空间;

  5. 尽量少用 text 类型,非用不可时最好考虑分表;

  6. 尽量使用 timestamp,而非 datetime;

  7. 单表不要有太多字段,建议在 20 个字段以内。

问题 2:部分 SQL 运行慢

问题分析

部分 SQL 运行比较慢,我们首先要做的就是先定位出这些 SQL,然后再看这些 SQL 是否正确创建并使用索引。也就是说,我们先要使用慢查询工具定位出具体的 SQL,然后再使用问题 1 的解决方案处理慢 SQL。

解决方案:慢查询分析

MySQL 中自带了慢查询日志的功能,开启它就可以用来记录在 MySQL 中响应时间超过阀值的语句,具体指运行时间超过 long_query_time 值的 SQL,则会被记录到慢查询日志中。long_query_time 的默认值为 10,意思是运行 10S 以上的语句。默认情况下,MySQL 数据库并不启动慢查询日志,需要我们手动来设置这个参数,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会给 MySQL 服务器带来一定的性能影响。慢查询日志支持将日志记录写入文件,也支持将日志记录写入数据库表。使用 mysql> show variables like '%slow_query_log%'; 来查询慢查询日志是否开启,执行效果如下图所示:slow_query_log 的值为 OFF 时,表示未开启慢查询日志。

开启慢查询日志

开启慢查询日志,可以使用如下 MySQL 命令:

mysql> set global slow_query_log=1

不过这种设置方式,只对当前数据库生效,如果 MySQL 重启也会失效,如果要永久生效,就必须修改 MySQL 的配置文件 my.cnf,配置如下:

slow_query_log =1 slow_query_log_file=/tmp/mysql_slow.log

当你开启慢查询日志之后,所有的慢查询 SQL 都会被记录在 slow_query_log_file 参数配置的文件内,默认是 /tmp/mysql_slow.log 文件,此时我们就可以打开日志查询到所有慢 SQL 进行逐个优化。

问题 3:整个 SQL 运行慢

问题分析

当出现整个 SQL 都运行比较慢就说明目前数据库的承载能力已经到了峰值,因此我们需要使用一些数据库的扩展手段来缓解 MySQL 服务器了。

解决方案:读写分离

一般情况下对数据库而言都是“读多写少”,换言之,数据库的压力多数是因为大量的读取数据的操作造成的,我们可以采用数据库集群的方案,使用一个库作为主库,负责写入数据;其他库为从库,负责读取数据。这样可以缓解对数据库的访问压力。

MySQL 常见的读写分离方案有以下两种:

1.应用层解决方案

可以通过应用层对数据源做路由来实现读写分离,比如,使用 SpringMVC + MyBatis,可以将 SQL 路由交给 Spring,通过 AOP 或者 Annotation 由代码显示的控制数据源。优点:路由策略的扩展性和可控性较强。缺点:需要在 Spring 中添加耦合控制代码。

2.中间件解决方案

通过 MySQL 的中间件做主从集群,比如:Mysql Proxy、Amoeba、Atlas 等中间件都能符合需求。优点:与应用层解耦。缺点:增加一个服务维护的风险点,性能及稳定性待测试,需要支持代码强制主从和事务。

扩展知识:SQL 语句分析

在 MySQL 中我们可以使用 explain 命令来分析 SQL 的执行情况,比如:

explain select * from t where id=5;

如下图所示:

其中:

  • id — 选择标识符,id 越大优先级越高,越先被执行;

  • select_type — 表示查询的类型;

  • table — 输出结果集的表;

  • partitions — 匹配的分区;

  • type — 表示表的连接类型;

  • possible_keys — 表示查询时,可能使用的索引;

  • key — 表示实际使用的索引;

  • key_len — 索引字段的长度;

  • ref—  列与索引的比较;

  • rows — 大概估算的行数;

  • filtered — 按表条件过滤的行百分比;

  • Extra — 执行情况的描述和说明。

其中最重要的就是 type 字段,type 值类型如下:

  • all — 扫描全表数据;

  • index — 遍历索引;

  • range — 索引范围查找;

  • index_subquery — 在子查询中使用 ref;

  • unique_subquery — 在子查询中使用 eq_ref;

  • ref_or_null — 对 null 进行索引的优化的 ref;

  • fulltext — 使用全文索引;

  • ref — 使用非唯一索引查找数据;

  • eq_ref — 在 join 查询中使用主键或唯一索引关联;

  • const — 将一个主键放置到 where 后面作为条件查询, MySQL 优化器就能把这次查询优化转化为一个常量,如何转化以及何时转化,这个取决于优化器,这个比 eq_ref 效率高一点。

总结

本文我们介绍了 MySQL 性能优化的原则和分类,MySQL 的性能优化可分为:主动优化和被动优化,但无论何种优化都要保证服务的正确性、安全性和稳定性。它带给我们的启发是应该采用:预防 + 被动优化的方案来确保 MySQL 服务器的稳定性,而被动优化常见的问题是:

  • 单条 SQL 运行慢;

  • 部分 SQL 运行慢;

  • 整个 SQL 运行慢。

因此我们给出了每种被动优化方案的问题分析和解决方案,希望本文可以帮助到你。

  最后的话原创不易,都看到这了,点个「赞」再走呗,这是对我最大的支持与鼓励,谢谢你!往期推荐

阿里《Java开发手册》最新嵩山版发布!


池化技术到达有多牛?看了线程和线程池的对比吓我一跳!

关注下方二维码,每一天都有干货!

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

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

相关文章

PLSQL_性能优化系列10_Oracle Array数据组优化

2014-09-25 Created By BaoXinjian 一、摘要 集合是Oracle开发中经常遇到的情况&#xff0c;Oracle集合分为三种情况&#xff1a;索引表集合(index by table)、嵌套表集合(nested table)、可变集合(varry table)。 PL/SQL中没有数组的概念&#xff0c;他的集合数据类型和数组是…

IDEA 2020.2 重磅发布,动画级新功能预览!

Guide 关注了 IDEA 的官推&#xff0c;平时没事就会去看看有没有啥比较好的更新。今天下午看到IntelliJ IDEA 2020.2 都已经发布并且还支持了 Java15。然后&#xff0c;我就去官网简单看了一下新特性。单看新特性&#xff0c;这个新版本还是有一点香的。虽然我还木有升级到这个…

访问控制模型ACL和RBAC

2019独角兽企业重金招聘Python工程师标准>>> 1.ACL ACL是最早也是最基本的一种访问控制机制&#xff0c;它的原理非常简单&#xff1a;每一项资源&#xff0c;都配有一个列表&#xff0c;这个列表记录的就是哪些用户可以对这项资源执行CRUD中的那些操作。当系统试图…

最常见并发面试题整理!(速度收藏)

前言并发编程是面试中必问的知识点之一&#xff0c;所以本文整理了一些最为常见的并发面试题&#xff0c;一起来看吧~1. synchronized的实现原理以及锁优化&#xff1f;synchronized的实现原理synchronized作用于「方法」或者「代码块」&#xff0c;保证被修饰的代码在同一时间…

JavaScript中的嵌套事件处理(在鼠标移动事件上)

Multiple event handling is the secret ingredient of dynamic WebPages seen now-a-days. 多重事件处理是当今动态网页的秘密组成部分。 Now, let’s get started... 现在&#xff0c;让我们开始吧... Example Code 范例程式码 <html lang"en"><head&…

皮尔逊相关性_皮尔逊的相关性及其在机器学习中的意义

皮尔逊相关性Today we would be using a statistical concept i.e. Pearsons correlation to help us understand the relationships between the feature values (independent values) and the target value (dependent value or the value to be predicted ) which will furt…

磊哥最近面试了好多人,聊聊我的感受!(附面试知识点)

这是我的第 84 篇原创文章作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;一些读者可能知道&#xff0c;磊哥前段时间又回来上班了&#xff0c;详见《磊哥又滚回职场了...》…

M4 宏处理器

2019独角兽企业重金招聘Python工程师标准>>> M4 宏处理器 Brian W. KernighanDennis M. Ritchie Bell LaboratoriesMurray Hill, New Jersey 07974 翻译&#xff1a;寒蝉退士 译者声明&#xff1a;译者对译文不做任何担保&#xff0c;译者对译文不拥有任何权利并且不…

绝了,几款主流的 JSON 库性能对比!

本篇通过JMH&#xff08;Oracle官方测试框架&#xff09;来测试一下Java中几种常见的JSON解析库的性能。每次都在网上看到别人说什么某某库性能是如何如何的好&#xff0c;碾压其他的库。但是百闻不如一见&#xff0c;只有自己亲手测试过的才是最值得相信的。JSON不管是在Web开…

DWZ使用笔记

DWZ使用笔记 一、前言 在近期的一个项目中&#xff0c;引入了DWZ这个富client框架&#xff0c;算是一次尝试吧。期间也遇到不少问题&#xff0c;总算一一攻克了。特以此文记之。本人用的是dwz-ria-1.4.5Asp.net webform&#xff0c;写这篇笔记时最新版本号已经是1.4.6了。DWZ官…

阿里的简历多久可以投递一次?次数多了有没有影响?可以同时进行吗?

最近&#xff0c;无论是读者群&#xff0c;还是公众号后台&#xff0c;很多人都比较关注以下几个问题&#xff1a;阿里的简历是半年只能投递一次吗&#xff1f;阿里的面试可以多个部门同时进行吗&#xff1f;面试没过&#xff0c;又被系统捞起来了&#xff0c;我该怎么办&#…

记一次蚂蚁金服面试被虐经历

本文来自作者投稿&#xff0c;原作者&#xff1a;yes面试前的小姐姐来说说前不久蚂蚁金服一面的情况。说来也是巧合&#xff0c;当时在群里有位蚂蚁金服的小姐姐发了个内推&#xff0c;看了下JD感觉可以试试于是就私聊了小姐姐发简历内推了。我16年也就是大三上就开始实习了&am…

用python + openpyxl处理excel(07+)文档 + 一些中文处理的技巧

2019独角兽企业重金招聘Python工程师标准>>> 寻觅工具 确定任务之后第一步就是找个趁手的库来干活。 Python Excel上列出了xlrd、xlwt、xlutils这几个包&#xff0c;但是 它们都比较老&#xff0c;xlwt甚至不支持07版以后的excel它们的文档不太友好&#xff0c;都可…

Spring Boot 2.3.3 正式发布!

Spring Boot 2.3.3 稳定版已发布&#xff0c;可从 repo.spring.io 和 Maven Central 获取。<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</versio…

木板最优切割利润最大_最多进行K笔交易的股票最大买卖利润

木板最优切割利润最大This is a very popular interview problem to find maximum profit in stock buying and selling with at most K transactions. This problem has been featured in the interview rounds of Amazon. 这是一个非常受欢迎的面试问题&#xff0c;目的是在最…

[数据库]Oracle和mysql中的分页总结

Mysql中的分页物理分页•在sql查询时&#xff0c;从数据库只检索分页需要的数据•通常不同的数据库有着不同的物理分页语句•mysql物理分页&#xff0c;采用limit关键字•例如&#xff1a;检索11-20条 select * from user limit 10,10 ;* 每次只查询10条记录.当点击下一页的时候…

List 集合去重的 3 种方法

问题由来在实际开发的时候&#xff0c;我们经常会碰到这么一个困难&#xff1a;一个集合容器里面有很多重复的对象&#xff0c;里面的对象没有主键&#xff0c;但是根据业务的需求&#xff0c;实际上我们需要根据条件筛选出没有重复的对象。比较暴力的方法&#xff0c;就是根据…

C语言入门——排序

排序的方法有很多种比较常见的便为&#xff1a;冒泡排序、选择排序、插入排序、快速排序。 今天我们就围绕着四种排序来说&#xff0c;如果有兴趣的话可以去查找一下其他排序。 在排序这方面我们主要讨论&#xff1a; 稳定&#xff1a;如果a原本在b前面&#xff0c;而ab&…

【转】eclipse技巧1

2019独角兽企业重金招聘Python工程师标准>>> 俗话说的好啊&#xff0c;“工于利启事&#xff0c;必先善其器”&#xff0c;如果说你的编程功底是一个枪法的话&#xff0c;那么强大的eclipse就是android战士们最好的武器。 这里&#xff0c;我们来总结eclipse的使用技…

定时任务最简单的3种实现方法(超好用)

这是我的第 86 篇原创文章作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;定时任务在实际的开发中特别常见&#xff0c;比如电商平台 30 分钟后自动取消未支付的订单&#x…