MySQL-性能优化_大表和大事务的常用处理方案

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL DuckDB 分析主实例,集群系列 8核16GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: MySQL-性能优化_大表和大事务的常用处理方案

20200129003012618.png

生猛干货

带你搞定MySQL实战,轻松对应海量业务处理及高并发需求,从容应对大场面试


官方文档

https://dev.mysql.com/doc/


20200131202811239.png


如果英文不好的话,可以参考 searchdoc 翻译的中文版本

http://www.searchdoc.cn/rdbms/mysql/dev.mysql.com/doc/refman/5.7/en/index.com.coder114.cn.html


20200131203226295.png


影响MySQL性能的几大因素


通常来说 ,有以下几点

慢SQL(重点) 、 主机的硬件资源(CPU、内存、磁盘I/O等)、网卡流量等等


超高的QPS和 TPS


QPS(Queries Per Second 每秒处理的查询量) : 假设处理一个SQL 需要 10ms , 1s 最多也就处理100个,那么QPS < = 100 ,如果 100ms处理一个呢? 那 QPS <=10 ,可以推断出SQL的执行效率队QPS的影响很重要。 一般来说,80%的数据库问题都可以通过SQL优化来解决。


TPS(Transactions Per Second,事务数/秒,这个完整的事务包括了用户请求服务器,服务器内部处理,服务器返回信息给用户三个过程)


QPS和TPS高,说明应用的负载较高.


MySQL数据库中的QPS和TPS的计算方法

Questions = SHOW GLOBAL STATUS LIKE 'Questions';
Uptime = SHOW GLOBAL STATUS LIKE 'Uptime';
QPS=Questions/Uptime
-----------------------
Com_commit = SHOW GLOBAL STATUS LIKE 'Com_commit';
Com_rollback = SHOW GLOBAL STATUS LIKE 'Com_rollback';
Uptime = SHOW GLOBAL STATUS LIKE 'Uptime';
TPS=(Com_commit + Com_rollback)/Uptime


高并发和高CPU使用率


高并发–>数据库连接池被用光的几率大增 (max_connections默认100),超过的话,就会看到500子类的错误了


高CPU使用率—>响应慢,甚至导致宕机


磁盘I/O


磁盘I/O的性能突然下降—>使用更快的磁盘设备


其他大量消耗磁盘性能的计划任务等 —> 可预期的高峰期,调整计划任务的执行时间


网卡流量


比如我们常说的千兆网卡, 这里的千兆 其实是 小b , 1Byte = 8 bit . bit 小b Byte 大B


1000Mb / 8 约等于 100MB (我们熟悉的带宽)


网卡被占满的风险增加 ,被占满的话,肯定访问不到数据库了 ,如何避免呢?


通常来说,


1. 减少slave节点的数量,避免大量的复制,占用带宽

2. 合理的使用多级缓存,避免大量缓存失效,请求到DB

3. 避免使用 select * 查询,占用带宽传输

3. 分离业务网络和服务器网络等等


大表带来的风险


大表的定义


啥叫大表? 粗略的定义 ,可以从两个维度去考虑,仅供参考

  1. 记录超过1千万
  2. 表数据文件巨大,超过10G


大表带来的风险


  • 对查询的影响
    举个例子: 从超巨数据中,查找区分度不高的数据,将导致大量的磁盘I/O,有可能导致数据库hang死 ,从而产生大量的慢查询,需要特别关注解决。
  • 对DDL的影响
  • 建立索引 耗时特别长, 风险: MySQL 5.5 以前的版本,建立索引会锁表 。 5.5以后的版本虽然不会引起锁表,但会引起主从延迟。
  • 修改表结构的话,需要长时间锁表 ,风险:1. 主从延迟 2. 影响正常的数据操作


如何应对大表?


  • 1. 分库分表 (分表主键如何选择,分表后跨分区的查询和统计如何解决) 慎重!!!
  • 2. 对历史数据进行归档 (归档时间点的选择 、如何高效的归档)


大事务带来的风险


基本特性:ACID


事务的4个特性: ACID

原子性 atomicity | 一致性 consistency | 隔离性 isolation | 持久性 durability


原子性(atomicity)

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。


举个例子: 转账 A 转给B , A账户 扣减 2千, B账户 增加两千 。 这两个必须在一个事务中,有任何一步出现问题,都不会提交,需要回滚, 否则的话,A扣了2000成功,B增加2000没成功,钱就莫名其妙的少了,谁能受得了?


一致性 consistency


一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。


说实话,这个定义太难懂了。。。。


[1]Transactions are not a law of nature; they were created with a purpose, namely to simplify the programming model for applications accessing a database. By using transactions, the application is free to ignore certain potential error scenarios and concurrency issues, because the database takes care of them instead (we call these safety guarantees).


上述说出了为什么会出现事务 : 事务的产生,其实是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题。 因此事务本质上是为了应用层服务的。


ACID里的AID都是数据库的特征,也就是依赖数据库的具体实现.而唯独这个C,实际上它依赖于应用层,也就是依赖于开发者.


一致性是指系统从一个正确的状态,迁移到另一个正确的状态.什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态.而事务具备ACID里C的特性是说通过事务的AID来保证我们的一致性.


CASE1: A要向B转2000元,而A的账户中只有1800元,并且我们给定账户余额这一列的约束是,不能小于0.那么很明显这条事务执行会失败,因为1800-2000=-200,小于我们给定的约束了. -----------------> 这个例子里,支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功了,我们的数据库数据就破坏约束了,因此事务不能成功,这里我们说事务提供了一致性的保证 .


CASE2: A要向B支付2000元,而A的账户中只有1800元,我们的账户余额列没有任何约束.但是我们业务上不允许账户余额小于0.因此支付完成后我们会检查A的账户余额,发现余额小于0了,于是我们进行了事务的回滚. -------------------> 这个例子里,如果事务执行成功,虽然没有破坏数据库的约束,但是破坏了我们应用层的约束.而事务的回滚保证了我们的约束,因此也可以说事务提供了一致性保证. (事实上,是我们应用层利用事务回滚保证了我们的约束不被破坏)


CASE3: A要向B支付2000元,而A的账户中只有1800元,我们的账户余额列没有任何约束.然后支付成功了.-------------------->这里,如果按照很多人的理解,事务不是保证一致性么?直观上账户余额为什么能为负呢.但这里事务执行前和执行后,我们的系统没有任何的约束被破坏.一直都是保持正确的状态.


所以,综上.我们可以理解一致性就是:应用系统从一个正确的状态到另一个正确的状态.而ACID就是说事务能够通过AID来保证这个C的过程.C是目的,AID都是手段.


隔离性 isolation


一个事务所做的修改在最终提交以前,对其他事务是不可见的。


还是转账的例子 ,A转账给B,A扣减,B增加。 假设在A扣减完成,B未增加时, 有另外一个事务,统计A账户的余额 ,这个时候看到的应该是A扣减前的金额。


持久性 durability

事务的操作,一旦提交,对于数据库中数据的改变是永久性的,即使数据库发生故障也不能丢失已提交事务所完成的改变。


SQL标准中的4个隔离级别


Read UnCommitted 读取未提交内容


在这个隔离级别,所有事务都可以“看到”未提交事务的执行结果。在这种级别上,可能会产生很多问题,除非用户真的知道自己在做什么,并有很好的理由选择这样做。本隔离级别很少用于实际应用,因为它的性能也不必其他性能好多少,而别的级别还有其他更多的优点。读取未提交数据,也被称为“脏读”


Read Committed 读取提交内容 (oracle等大部分数据库的隔离级别)


大多数数据库系统的默认隔离级别(但是不是MySQL的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能“看见”已经提交事务所做的改变,一个事务从开始到提交前,所做的任何数据改变都是不可见的,除非已经提交。


这种隔离级别被称为“不可重复读”。这意味着用户运行同一个语句两次,看到的结果是不同的。


Repeatable Read 可重复读 (MySQL默认的隔离级别)


MySQL数据库默认的隔离级别。该级别解决了READ UNCOMMITTED隔离级别导致的问题。它保证同一事务的多个实例在并发读取事务时,会“看到同样的”数据行。不过,这会导致另外一个棘手问题“幻读”。InnoDB和Falcon存储引擎通过多版本并发控制机制解决了幻读问题。


Serializable 可串行化


该级别是最高级别的隔离级。它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,SERIALIZABLE是在每个读的数据行上加锁。在这个级别,可能导致大量的超时Timeout和锁竞争Lock Contention现象,实际应用中很少使用到这个级别,但如果用户的应用为了数据的稳定性,需要强制减少并发的话,也可以选择这种隔离级


Read Committed (不可重复读) VS Repeatable Read (可重复读) VS Read UnCommitted(脏读)


我们以MySQL数据库为例子,对比下这两种事务隔离级别对查询数据的影响


打开两个会话

会话一 :

# 连接mysql
[root@artisan ~]# mysql -u root -p
Enter password:
 ....
 ....
 ....
 ....
# 切到artisan数据库
mysql> use artisan;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> desc t_test;  # 查看t_test表结构
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
mysql> select * from t_test; # 查询数据
+----+
| id |
+----+
|  1 |
|  3 |
|  5 |
|  7 |
|  9 |
+----+
5 rows in set (0.00 sec)
mysql> show variables like '%iso%'  # 查看隔离级别 
    -> ;
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
| tx_isolation          | REPEATABLE-READ |
+-----------------------+-----------------+
2 rows in set (0.00 sec)
mysql> begin;   # 开启事务 
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_test where id < 7;
+----+
| id |
+----+
|  1 |
|  3 |
|  5 |
+----+
3 rows in set (0.00 sec)
mysql> 


然后 切到会话二 ,插入几条数据

[root@artisan ~]# mysql -u root -p
Enter password: 
.....
.....
.....
mysql> use artisan;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> select * from t_test;
+----+
| id |
+----+
|  1 |
|  3 |
|  5 |
|  7 |
|  9 |
+----+
5 rows in set (0.00 sec)
mysql> begin ;  # 开启事务
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_test values(2);  #插入数据 
Query OK, 1 row affected (0.00 sec)
mysql> commit;   #提交事务
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_test; 
+----+
| id |
+----+
|  1 |
|  3 |
|  5 |
|  7 |
|  9 |
|  2 |
+----+
6 rows in set (0.00 sec)
mysql> 


重新切回到 会话一,重复执行刚才的SQL (此时,会话一这个事务还未提交,还在事务中)


20200129131906649.png


可以看到,在 **REPEATABLE-READ (可重复读)**这种隔离级别下, 事务一 在事务内,每次查询到的数据都是一样的,而且也无法读取到事务二已经提交的数据。


这也就理解了为啥叫 “可重复读” : 因为 它保证同一事务的多个实例在并发读取事务时,会“看到同样的”数据行 。


那 这种事务级别潜在的问题是啥呢 ? --------> 会导致另外一个棘手问题“幻读”。InnoDB和Falcon存储引擎通过多版本并发控制机制解决了幻读问题。


幻读是事务非独立执行时发生的一种现象,例如事务T1批量对一个表中某一列列值为1的数据修改为2的变更,但是在这时,事务T2对这张表插入了一条列值为1的数据,并完成提交。此时,如果事务T1查看刚刚完成操作的数据,发现还有一条列值为1的数据没有进行修改,而这条数据其实是T2刚刚提交插入的,这就是幻读


我们修改下 MySQL的隔离级别为 read-committed

我们把会话一的事务先提交了,然后修改下隔离级别

mysql> commit ;
Query OK, 0 rows affected (0.00 sec)
mysql> set session tx_isolation='read-committed';   # 设置隔离级别
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show variables like '%iso%'   
    -> ;   #查看隔离级别
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
| tx_isolation          | READ-COMMITTED |
+-----------------------+----------------+
2 rows in set (0.01 sec)
mysql> 


然后切到会话二


20200129135932408.png

回切到会话一,重新查询

20200129140033352.png


所以 READ-COMMITTED 又被称为不可重复读 ,因为对于数据库中的某个数据,一个事务执行过程中多次查询返回不同查询结果,这就是在事务执行过程中,数据被其他事务提交修改了。 每次查询都有可能查询到其他事务修改过的数据,所以称为 不可重复读。


不可重复读 VS 脏读 VS 可重复读


不可重复读同脏读的区别在于,脏读是一个事务读取了另一未完成的事务执行过程中的数据,而不可重复读是一个事务执行过程中,另一事务提交并修改了当前事务正在读取的数据。

幻读和不可重复读都是读取了另一条已经提交的事务(这点同脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。


总结下不同隔离级别的缺点


20200129134359914.png


隔离行由低到高 : Read UnCommitted —> Read Committed —> Repeatable Read -----> Serializable


并发性由高到低 : Read UnCommitted —> Read Committed —> Repeatable Read -----> Serializable


MySQL修改隔离级别的方法

全局修改需要修改MySql的全局文件my.cnf (linux操作系统)

#可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
[mysqld]
transaction-isolation = REPEATABLE-READ

修改当前会话Session的隔离级

mysql> set session tx_isolation = 'REPEATABLE-READ';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show variables like '%iso%'
    -> ;
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
| tx_isolation          | REPEATABLE-READ |
+-----------------------+-----------------+
2 rows in set (0.00 sec)
mysql> 


MySql 的autoCommit设置

另外MySql中有autoCommit参数,默认为on,也就是开启状态

mysql>  show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)
mysql> 


如果需要关闭autocommit,我们可以使用下面语句设置

mysql> set autocommit=0;


0就是OFF,1就是ON。设置为OFF之后,则用户执行语句之后,将一直处于一个事务中,直到执行commit或者rollback,才会结束当前事务,重新开始新的事务。


大事务的定义


定义: 运行时间比较长,操作数据比较多的事务


大事务的潜在风险

  • 锁定太多的数据,容易造成阻塞和超时 。
  • 回滚时间耗时较长,回滚过程中也容易阻塞
  • 容易造成主从延迟

如何处理大事务

  • 避免一次处理太多数据
  • 移除事务中不必要的 select操作

搞定MySQL


https://artisan.blog.csdn.net/article/details/104103852?spm=1001.2014.3001.5502


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
3月前
|
SQL 关系型数据库 MySQL
MySQL锁机制:并发控制与事务隔离
本文深入解析了MySQL的锁机制与事务隔离级别,涵盖锁类型、兼容性、死锁处理及性能优化策略,助你掌握高并发场景下的数据库并发控制核心技巧。
|
3月前
|
运维 监控 关系型数据库
MySQL高可用方案:MHA与Galera Cluster对比
本文深入对比了MySQL高可用方案MHA与Galera Cluster的架构原理及适用场景。MHA适用于读写分离、集中写入的场景,具备高效写性能与简单运维优势;而Galera Cluster提供强一致性与多主写入能力,适合对数据一致性要求严格的业务。通过架构对比、性能分析及运维复杂度评估,帮助读者根据自身业务需求选择最合适的高可用方案。
|
4月前
|
存储 监控 Oracle
MySQL事务
MySQL事务具有ACID特性,包括原子性、一致性、隔离性和持久性。其默认隔离级别为可重复读,通过MVCC和间隙锁解决幻读问题,确保事务间数据的一致性和并发性。
MySQL事务
|
2月前
|
关系型数据库 MySQL 数据库
【赵渝强老师】MySQL的事务隔离级别
数据库并发访问时易引发数据不一致问题。如客户端读取到未提交的事务数据,可能导致“脏读”。MySQL通过四种事务隔离级别(读未提交、读已提交、可重复读、可序列化)控制并发行为,默认为“可重复读”,以平衡性能与数据一致性。
257 0
|
4月前
|
存储 关系型数据库 MySQL
修复.net Framework4.x连接MYSQL时遇到utf8mb3字符集不支持错误方案。
通过上述步骤大多数情况下能够解决由于UTF-encoding相关错误所带来影响,在实施过程当中要注意备份重要信息以防止意外发生造成无法挽回损失,并且逐一排查确认具体原因以采取针对性措施解除障碍。
260 12
|
3月前
|
关系型数据库 MySQL 数据库
MySql事务以及事务的四大特性
事务是数据库操作的基本单元,具有ACID四大特性:原子性、一致性、隔离性、持久性。它确保数据的正确性与完整性。并发事务可能引发脏读、不可重复读、幻读等问题,数据库通过不同隔离级别(如读未提交、读已提交、可重复读、串行化)加以解决。MySQL默认使用可重复读级别。高隔离级别虽能更好处理并发问题,但会降低性能。
152 0
|
5月前
|
SQL 关系型数据库 MySQL
解决MySQL "ONLY_FULL_GROUP_BY" 错误的方案
在实际操作中,应优先考虑修正查询,使之符合 `ONLY_FULL_GROUP_BY`模式的要求,从而既保持了查询的准确性,也避免了潜在的不一致和难以预测的结果。只有在完全理解查询的业务逻辑及其后果,并且需要临时解决问题的情况下,才选择修改SQL模式或使用 `ANY_VALUE()`等方法作为短期解决方案。
644 8
|
4月前
|
监控 NoSQL 关系型数据库
保障Redis与MySQL数据一致性的强化方案
在设计时,需要充分考虑到业务场景和系统复杂度,避免为了追求一致性而过度牺牲系统性能。保持简洁但有效的策略往往比采取过于复杂的方案更加实际。同时,各种方案都需要在实际业务场景中经过慎重评估和充分测试才可以投入生产环境。
244 0
|
5月前
|
安全 关系型数据库 MySQL
mysql事务隔离级别
事务隔离级别用于解决脏读、不可重复读和幻读问题。不同级别在安全与性能间权衡,如SERIALIZABLE最安全但性能差,READ_UNCOMMITTED性能高但易导致数据不一致。了解各级别特性有助于合理选择以平衡并发性与数据一致性需求。
183 1
|
5月前
|
存储 SQL 关系型数据库
MySQL 核心知识与性能优化全解析
我整理的这份内容涵盖了 MySQL 诸多核心知识。包括查询语句的书写与执行顺序,多表查询的连接方式及内、外连接的区别。还讲了 CHAR 和 VARCHAR 的差异,索引的类型、底层结构、聚簇与非聚簇之分,以及回表查询、覆盖索引、左前缀原则和索引失效情形,还有建索引的取舍。对比了 MyISAM 和 InnoDB 存储引擎的不同,提及性能优化的多方面方法,以及超大分页处理、慢查询定位与分析等,最后提到了锁和分库分表可参考相关资料。
130 0

推荐镜像

更多