MySQL的主动优化和被动优化_MySQL“被动”性能优化汇总!

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

本文内容导图如下:

a0a8c5e822bd4093bd67ceb023b52528.png

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

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

020b08a77108ae782e4f86a3a6d7632c.png

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

性能优化原则和分类

性能优化一般可以分为:主动优化

被动优化

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

c92699669d94481ccdc1ef809f9d6849.png

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

性能优化原则

无论是主动优化还是被动优化都要符合以下性能优化的原则:优化不能改变服务运行的逻辑,要保证服务的正确性;

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

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

b0055cc54f4d00f4609ffe8cef5d0f08.png

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

也就是说,我们应该以预防性能问题为主,在开发阶段尽可能的规避性能问题,而在正常情况下,应尽量避免主动优化,以防止未知的风险(除非是为了 KPI,或者是闲的没事),尤其对生产环境而言更是如此,最后才是考虑被动优化。PS:当遇到性能缓慢下降、或硬件指标缓慢增加的情况,如今天内存的占用率是 50%,明天是 70%,后天是 90% ,并且丝毫没有收回的迹象时,我们应该提早发现并处理此类问题(这种情况也属于被动优化的一种)。

MySQL 被动性能优化

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

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

部分 SQL 运行慢;

整个 SQL 运行慢。

fd79bf973243b8f374c4489675b1444e.png

问题 1:单条 SQL 运行慢

问题分析

造成单条 SQL 运行比较慢的常见原因有以下两个:未正常创建或使用索引;

表中数据量太大。

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

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

如果表的索引已经创建了,接下来就要检查一下此 SQL 语句是否正常触发了索引查询,如果发生以下情况那么 MySQL 将不能正常的使用索引:在 where 子句中使用 != 或者 <> 操作符,查询引用会放弃索引而进行全表扫描;

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

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

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

因此你要尽量避免以上情况,除了正常使用索引之外,我们也可以使用以下技巧来优化索引的查询速度:尽量使用主键查询,而非其他索引,因为主键查询不会触发回表查询;

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

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

用 exists 替代 in 查询;

避免在索引列上使用 is null 和 is not null。回表查询:普通索引查询到主键索引后,回到主键索引树搜索的过程,我们称为回表查询。

解决方案 2:数据拆分

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

1.垂直拆分

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

垂直拆分的原则:把不常用的字段单独放在一张表;

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

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

2.水平拆分

指的是将数据表行进行拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。

通常情况下,我们使用取模的方式来进行表的拆分,比如,一张有 400W 的用户表 users,为提高其查询效率我们把其分成 4 张表 users1,users2,users3,users4,然后通过用户 ID 取模的方法,同时查询、更新、删除也是通过取模的方法来操作。

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

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

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

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

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

尽量使用 timestamp,而非 datetime;

单表不要有太多字段,建议在 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%'; 来查询慢查询日志是否开启,执行效果如下图所示:

f032a5431f327f068cbf08de903afcc9.png

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;

如下图所示:

3d7fc037d6ac971a69238468312100aa.png

其中: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/372191.shtml

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

相关文章

python2

一、管理库的安装 安装pip 提示报错&#xff1a;安装pip提示No module named setuptools Windows环境下Python默认是没有安装setuptools这个模块的&#xff0c;这也是一个第三方模块。下载地址为http://pypi.python.org/pypi/setuptools。下载后直接运行ez_setup.py 参考地址&…

Java Mybatis

Mybatis转载于:https://www.cnblogs.com/leading-index/p/6853031.html

Java例外:java lang NoSuchMethodError

如果查看错误消息java.lang.NoSuchMethodError&#xff0c;您可能会理解Java虚拟机正在尝试向我们表明您调用的方法在类或接口中不可用。 您还可能在执行没有公共static void main&#xff08;&#xff09;方法的类时抛出此错误。要了解其背后的原因&#xff0c;请阅读本文。 …

【图】最短路径——Floyed算法和Dijkstra算法

最短路径问题(floyed.cpp dijkstra.cpp) 题目描述平面上有n个点(n<100)&#xff0c;每个点的坐标均在-10000&#xff5e;10000之间。其中的一些点之间有连线。若有连线&#xff0c;则表示可从一个点到达另一个点&#xff0c;即两点间有通路&#xff0c;通路的距离为两点间的…

java的empty_Java Stack empty()方法与示例

堆栈类empty()方法empty()方法在java.util包中可用。empty()方法用于检查此堆栈是否为空。empty()方法是一个非静态方法&#xff0c;只能通过类对象访问&#xff0c;如果尝试使用类名称访问该方法&#xff0c;则会收到错误消息。在检查空状态时&#xff0c;empty()方法不会引发…

Java并发– CyclicBarrier示例

Java中的CyclicBarrier是JDK 5中java.util.Concurrent包中引入的同步器&#xff0c;以及其他并发实用程序&#xff08;如Counting Semaphore &#xff0c; BlockingQueue &#xff0c; ConcurrentHashMap等&#xff09;。CyclicBarrier与CountDownLatch类似&#xff0c;我们在上…

java i o总结_Java I/O 总结

一、IO流的三种分类方式1.按流的方向分为&#xff1a;输入流和输出流2.按流的数据单位不同分为&#xff1a;字节流和字符流3.按流的功能不同分为&#xff1a;节点流和处理流二、IO流的四大抽象类&#xff1a;字符流&#xff1a;Reader Writer字节流&#xff1a;InputStream(读数…

try...catch 语句

一般情况下&#xff0c;我们很少用到 try...catch 语句&#xff0c;但是有时候为了测试代码中的错误&#xff0c;也有可能会用到。小白我也在工作中用到过。那么好的程序设计&#xff0c;什么时候会用到呢&#xff1f; try...catch 一般用来捕获宿主对象或者ECMAScript抛出的异…

用Mockito回答

在编写单元测试时 &#xff0c;必须牢记不要依赖外部组件。 为了避免这种情况&#xff0c;我们使用了模拟框架&#xff0c;对我来说&#xff0c;最容易使用的是Mockito 。 在本文中&#xff0c;我们将看到在Mockito中使用的一种“高级”技术&#xff0c;可以使用Answer接口在模…

java三板斧_Java 枚举使用三板斧

Java 枚举使用三板斧1 定义public enum CountryEnums {ONE(1,"韩"),TWO(2,"魏"),THREE(3,"楚"),FOUR(4,"燕"),FIVE(5,"赵"),SIX(6,"齐");private Integer retCode;private String retMsg;// 枚举的构造方法是 pri…

假装这些是MyEclipse的快捷键(1)

Java快捷键 Alt / 代码自动补全Alt Shift S 功能菜单 Ctrl 1 代码自动修正Ctrl / 单行注释/取消Ctrl O 查看类的所有方法Ctrl T 查看类的集成架构图Ctrl Shift / 多行注释Ctrl Shift \ 取消多行注释Ctrl Shift F 代码格式化转载于:https://www.cnblogs.com/swordt…

JasperReports JSF插件用例–简单列表报告

这是JasperReports JSF插件系列的第一篇“用例文章” &#xff0c;我将专注于一个简单的需求&#xff0c;并且我将进一步深入。 起点是我们已经为图书商店完成的项目设置&#xff0c;我将向其中添加一个列表&#xff0c;其中包含在数据库中注册的其他图书&#xff0c;该列表也将…

2016.10.17先占坑

2016.10.17先占坑转载于:https://www.cnblogs.com/amurzet/p/5978986.html

ER图流程图

ER图&#xff1a;ER图分为实体、属性、关系三个核心部分。实体是长方形体现&#xff0c;而属性则是椭圆形&#xff0c;关系为菱形。 图书馆管理系统流程图&#xff08;图片源于网上&#xff09;&#xff1a;对于程序员来说&#xff0c;我们要知道&#xff1a;整个系统中&#x…

php源码仿三一重工,织梦仿三一重工业大学气企业网站php源码

★模板引荐★源码称呼&#xff1a;仿三一重工业大学气企业网站php源码仿三一重工业大学气企业网站php源码&#xff0c;尝试完备无错&#xff0c;兼容合流欣赏器。模板包括安置证明&#xff0c;并包括尝试数据。本模板鉴于DEDECms 5.7 GBK安排&#xff0c;须要 UTF-8版本的请本人…

接触Jenkins(Hudson)API,第2部分

这篇文章从本教程的第1部分继续。 已经快一年了&#xff0c;但是我终于有时间重新审视我为与Jenkins api交互而编写的一些代码。 我已经使用了部分工作来帮助管理许多Jenkins构建服务器&#xff0c;主要是保持插件同步以及将作业从一台机器移动到另一台机器。 在本文中&#xf…

php树莓派魔镜,用树莓派和显示器制作一面“魔镜”

所需要的材料一台显示器一块和显示器大小相同的双面镜一些2*4米的细木条树莓派机器必要组件(电源、HDMI线、usb无线网卡、键盘)木工工具(锯子、磨砂机、螺丝刀)螺丝、液态钉子选一个合适的显示器镜子的大小完全由显示器的类型和大小决定&#xff0c;所以我希望得到一个尽量大的…

【数字图像处理】[3]--直方图规范化

【数字图像处理】[3]--直方图规范化直方图规范化出现的原因是因为直方图均衡只能产生出固定的图像&#xff0c;不满足于需求&#xff0c;有时我们需要让直方图变成特定的直方图&#xff0c;于是有了直方图规范化原理&#xff1a;可能只看公式没什么感觉&#xff0c;我们来举一个…

JavaFX 2.0布局窗格– GridPane

毫无疑问&#xff0c; GridPane是JavaFX 2.0中功能最强大&#xff0c;最灵活的布局窗格。 它在由行和列组成的灵活网格中布置其子项&#xff0c;与Swing的GridBagLayout或HTML的表格模型非常相似。 这种方法使该窗格非常适合于任何形式的表单&#xff08;例如网站上的联系表单&…

leecode 题解 || Merge k Sorted Lists 问题

problem&#xff1a; Merge k sorted linked lists and return it as one sorted list.Analyze and describe its complexity.Tags Divide and Conquer Linked List Heap合并K个已序单链表 thinking&#xff1a; &#xff08;1&#xff09;题目没有要求不能够新开ListNode,所以…