松哥有两个小伙伴最近在帮人改造一个系统,对方原本的系统是一个用 Java GUI 做的桌面应用,现在要用 Spring Boot 改造成一个 Web 应用。原本的应用在 Mac 上运行的时候非常丝滑,但是在 Windows 上运行的时候,就特别卡。经过分析之后,发现是因为数据库中数据量过大导致每一次的查询都非常缓慢。
为了解决这一问题,他们特地来咨询了松哥,我也趁此机会整理了一下数据库优化的基本操作,形成了几篇文章,接下来就和小伙伴们逐一分享。
今天我们主要来看下,到底是什么影响了数据库的性能?找到问题的原因,才能解决问题。
整体上来说,影响数据库性能的因素,我们可以归为以下几个方面:
- SQL 脚本
- 数据库服务器配置
- 网卡流量
- 磁盘 IO
- 大表操作
- 大事务操作
- 存储引擎
- 数据库参数配置
接下来我们就从这几个方面来逐一进行说明。
1. SQL 脚本
SQL 脚本会影响到 MySQL 的执行效率,这个大家都懂,面试八股文中常见问题之一。其实也不是面试官故意爱考这个问题,只是这个东西太重要了,根据松哥的经验,80% 的数据库问题,都是由慢 SQL 导致的,都可以通过 SQL 优化来解决,所以 SQL 优化技能对于开发者而言就非常重要了(有条件的公司也可以聘请 DBA,但是大部分公司是没有 DBA 的),这也是为什么我们在面试时经常会遇到 SQL 优化的原因。
那么慢 SQL 究竟会带来哪些风险呢?
超高的 QPS 和 TPS
可能有人还不清楚什么是 QPS 和 TPS,因此我们这里先对这两个做一个简单介绍。
- TPS:英文全称是 Transactions Per Second,即服务器每秒处理的事务数。TPS 包括一条消息入和一条消息出,加上一次用户数据库访问。这里涉及到一个概念,就是事务。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。
- QPS:英文全称是 Queries Per Second,即每秒查询率。QPS 是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。举个例子:假设数据库处理一条 SQL 需要 10ms,那么 1s 就可以处理 100 条 SQL,那么我们说它 QPS<=100;假设数据库处理一条 SQL 需要 100ms,那么 1s 就可以处理 10 条 SQL,那么我们说它 QPS<=10。
我们常用 QPS 和 TPS 来衡量 SQL 的处理效率。
数据库连接被占满
这个好理解,数据库的连接数必然是有限的,在 MySQL 中,我们可以通过 max_connections 来设置数据库的连接数(这个值默认是 100,生产环境下这个值可以适当调大)。慢 SQL 由于处理时间较长,因此占用数据库连接的时间也较长,在高并发环境下这样就容易导致数据库连接被占满。
超高的 CPU 使用率
慢 SQL 还会导致超高的 CPU 使用率,超高的 CPU 使用率会导致 CPU 资源耗尽进而出现宕机。
慢 SQL 真的危害很大!
2.数据库服务器配置
这个应该好理解,不需要我多说吧。
服务器的硬件如 CPU、内存、磁盘 IO 等都会影响到 MySQL 性能,操作系统也会影响到 MySQL 性能。
3.网卡流量
网卡流量当然也会影响数据库。网卡 IO 被占满了一样也是没法操作数据库,那么如何避免这一情况呢?
- 减少从服务器的数量,因为从服务器需要从主服务器同步数据,会占用网卡 IO(当然是在合理的范围内减少从服务器的数量)。
- 数据分级缓存,避免突然的缓存失效对数据库形成冲击。
- 避免 select *,不仅浪费时间,还浪费网络流量。
- 分离业务网络和服务器网络。
4.磁盘 IO
磁盘 IO 对数据库性能的影响也是显而易见的,因为数据库无论怎么管理数据,最终都是要存入到硬盘中的,所以磁盘 IO 对数据库的影响也就非常重要了。但是这个问题的解决,就只能使用更好更快的磁盘设备,例如 SSD。
另外,我们日常可能都会有一些定时的磁盘维护计划,在一些高并发场景下(如促销、618,双11等),我们就需要调整磁盘维护计划,避免在这些时候进行磁盘维护。同时一些大量消耗磁盘 IO 的工作如备份也需要在这个时候调整一下,例如原本在主库上做的数据备份工作,在大促期间可以放到从库上面做。
5.大表操作
大表操作也会影响到数据库性能,那么什么样的表就算大表呢?
大表没有统一的标准,还是要结合具体的业务场景来定。
我举一个比较常规的例子:
- 数据表中的行数超过千万行。
- 数据表文件超过 10G。
当然,上面这个定义并不是绝对的,如果是一个操作日志表,日志表一般只会涉及到插入和简单的查询,基本上不会有 delete 和 update,那么对于这种表,即使超过了千万行,也并不会影响我们的业务。但是如果是订单表等业务表,超过千万行就要小心了。
大表究竟会带来哪些问题呢?
- 慢查询:毕竟数据量大了,想要过滤出自己想要的数据,肯定费时间。从上千万上亿条数据中找出自己想要的数据,也会产生大量的磁盘 IO。
- DDL 操作恐怖:在大表上进行表定义操作也是一件非常恐怖的事情,例如建立索引、添加/删除 字段,想想都可怕。在 MySQL5.5(不含) 之前,建立索引是会锁表的,从 MySQL5.5(含) 开始,建立索引虽然不会锁表,但是会引起主从延迟(因为要在主库上操作完成之后,再将操作日志传到从库,然后完成同步)。
这就是大表所带来的问题,一般来说,我们有两种常见的解决思路:
- 分库分表
- 历史数据归档
至于什么时候用分库分表,什么时候用历史数据归档,这个松哥在以后的文章中再和大家介绍。
6.大事务操作
一些运行时间比较长,涉及到数据比较多的事务,我们可以称之为大事务。大事务会锁定很多条数据进行处理,这样就容易造成大量的阻塞和锁超时,并且一旦出错发生回滚,回滚所需要的时间也会比较长,而且在回滚期间数据依然处于被锁的状态。
同时,由于大事务耗时较长,需要等到主库事务执行完毕后,将操作日志写入 binlog,然后从库读取 binlog 进行同步,这样势必会导致主从延迟。
解决大事务,两个思路:
- 避免一次性处理太多数据。
- 移除事务中不必要的 SELECT 操作。
具体的操作方式,我们将在以后的文章中介绍。
7.存储引擎
使用 MySQL 我们可以选择不同的存储引擎,不同的存储引擎特点不同,最终对数据库的影响也不同。例如 MySQL 中常见的 MyISAM、InnoDB 等存储引擎。
MyISAM 不支持事务,而且是表级锁;InnoDB 是事务级存储引擎,支持行级锁,也支持事务的 ACID 特性。
那么是不是说 InnoDB 就一定比 MyISAM 好呢?也不一定!这个还是要看具体的使用场景。
8.数据库参数配置
大家都知道数据库有很多配置参数,我们在数据库优化时可对其进行配置,例如前面所说的 max_connections。这些参数中,有的参数对数据库的性能影响较大,有的则影响较小,这个我们在以后的文章中再和大家详细讨论。
好啦,今天主要和小伙伴们探讨了在我们日常开发中,到底有哪些东西会影响数据库的性能!至于具体的解决方案,松哥将在接下来的文章中和大家细聊。
虽然我们不是专业的 DBA,但是从小伙伴们的面试经历来看,数据库优化显然也不能一窍不通。