概要回顾

之前看过《高性能mysql》对mysql数据库有了系统化的理解,虽然没能达到精通,但有了概念,遇到问题时会有逻辑条理的分析;

这回继上次sql分析结果的一个继续延伸分析,我拿了;

备注:分析(除sql基本优化过程外)这个过程并定位到具体问题,给出针对性的解决方案,是一个非常漫长的过程,需要一个个的去排除和论证的过程;当对来说十分枯燥和窘境,但成功了就是一非常大的收获和经验;

-- ③ 优化前
select p.record_data,p.cooperation_name,p.cooperation_id,p.block_time,p.oss_volume as userOSSCapacity,p.txhash,p.seq_id,p.pre_seq_id,p.custom_string FROM poehistoryinfo p LEFT JOIN recordregistryinfo r ON p.record_registry_info_id=r.id LEFT JOIN identityinfo i ON i.account_id=r.mgmt_account_id where r.contract_address=? GROUP BY r.contract_address,p.record_data,p.cooperation_name,p.cooperation_id,p.block_time,p.txhash,p.seq_id,p.pre_seq_id,p.custom_string,p.oss_volume ORDER BY p.block_time DESC limit ?,? -- ③ 优化后
SELECT p.record_data,p.cooperation_name,p.cooperation_id,p.block_time,p.oss_volume as userOSSCapacity,p.txhash,p.seq_id,p.pre_seq_id,p.custom_string FROM poehistoryinfo p INNER JOIN
(SELECT p1.id FROM poehistoryinfo p1 LEFT JOIN recordregistryinfo r ON p1.record_registry_info_id=r.id LEFT JOIN identityinfo i ON i.account_id=r.mgmt_account_id where r.contract_address=? ORDER BY p1.block_time DESC limit ?,?) a ON a.id = p.id ;
--- 环境RDS 1C 1G mysql数据库,导入数据库,这时没有其他多余的IO读写操作
这回我申请了一个RDS 1C 1G mysql数据库,导入数据库,这时没有其他多余的IO读写操作;
效果:2条sql语句,
①优化前sql, 5.77ms
②优化后sql, 0.01ms 执行计划正常 --- 环境ECS 1C 1G自建数据库这是没有多余操作,这时没有其他多余的IO读写操作
ECS 自建数据库 1C 1G 这是没有多余操作,
效果:2条sql语句,
①优化前sql, 1.77ms
②优化后sql, 0.01ms 执行计划正常 --- 环境RDS 1C 1G mysql数据库,线上库,这时IOPS平均操作为300~400之间
我司生产上RDS 1C 1G 这时平均读写操作为300-400;
效果:2条sql语句,
①优化前sql, 5.89ms
②优化后sql, 6.35ms,不正常

问题

按mysql语句优化原则优化之后发现未达到预想的效果,问题如下:

  1. 在不优化的情况下自建数据库执行③slq语句比RDS数据库要快5倍以上;
  2. 优化之后的sql语句放到RDS上,比之前未优化的sql语句还慢;

分析思路

为了发现问题所以,我获取RDS 上的sql执行计划:

mysql> explain select p.record_data,p.cooperation_name,p.cooperation_id,p.block_time,p.oss_volume as userOSSCapacity,p.txhash,p.seq_id,p.pre_seq_id,p.custom_string FROM poehistoryinfo p LEFT JOIN recordregistryinfo r ON p.record_registry_info_id=r.id LEFT JOIN identityinfo i ON i.account_id=r.mgmt_account_id  where r.contract_address='85b692c81d16bfa49ce0b8a166458c71f522fd5b' GROUP BY r.contract_address,p.record_data,p.cooperation_name,p.cooperation_id,p.block_time,p.txhash,p.seq_id,p.pre_seq_id,p.custom_string,p.oss_volume ORDER BY p.block_time DESC limit 1,25;
id FROM poehistoryinfo p1 LEFT JOIN recordregistryinfo r ON p1.record_registry_info_id=r.id LEFT JOIN identityinfo i ON i.account_id=r.mgmt_account_id where r.contract_address='85b692c81d16bfa49ce0b8a166458c71f522fd5b' ORDER BY p1.block_time DESC limit 1,25;
+----+-------------+-------+------------+------+-----------------------------+-----------------------------+---------+------------------------+--------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-----------------------------+-----------------------------+---------+------------------------+--------+----------+----------------------------------------------------+
| 1 | SIMPLE | r | NULL | ALL | PRIMARY | NULL | NULL | NULL | 39 | 10.00 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | i | NULL | ref | identityinfo_account_id_ind | identityinfo_account_id_ind | 153 | sync.r.mgmt_account_id | 1 | 100.00 | Using where; Using index |
| 1 | SIMPLE | p | NULL | ALL | NULL | NULL | NULL | NULL | 172999 | 10.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+-----------------------------+-----------------------------+---------+------------------------+--------+----------+----------------------------------------------------+
3 rows in set, 1 warning (0.01 sec)
mysql> explain SELECT p.record_data,p.cooperation_name,p.cooperation_id,p.block_time,p.oss_volume as userOSSCapacity,p.txhash,p.seq_id,p.pre_seq_id,p.custom_string FROM poehistoryinfo p  INNER JOIN (SELECT p1.id FROM poehistoryinfo p1 LEFT JOIN recordregistryinfo r ON p1.record_registry_info_id=r.id LEFT JOIN identityinfo i ON i.account_id=r.mgmt_account_id  where r.contract_address='85b692c81d16bfa49ce0b8a166458c71f522fd5b' ORDER BY p1.block_time DESC limit 1,25) a ON a.id = p.id ;

+----+-------------+------------+------------+--------+-----------------------------+-----------------------------+---------+------------------------+--------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+-----------------------------+-----------------------------+---------+------------------------+--------+----------+----------------------------------------------------+
| 1 | PRIMARY | <derived2> | NULL | ALL | NULL | NULL | NULL | NULL | 26 | 100.00 | NULL |
| 1 | PRIMARY | p | NULL | eq_ref | PRIMARY | PRIMARY | 4 | a.id | 1 | 100.00 | NULL |
| 2 | DERIVED | r | NULL | ALL | PRIMARY | NULL | NULL | NULL | 39 | 10.00 | Using where; Using temporary; Using filesort |
| 2 | DERIVED | i | NULL | ref | identityinfo_account_id_ind | identityinfo_account_id_ind | 153 | sync.r.mgmt_account_id | 1 | 100.00 | Using where; Using index |
| 2 | DERIVED | p1 | NULL | ALL | NULL | NULL | NULL | NULL | 172999 | 10.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+------------+------------+--------+-----------------------------+-----------------------------+---------+------------------------+--------+----------+----------------------------------------------------+
5 rows in set, 1 warning (0.00 sec)

根据上面的分析和上篇ECS sql执行计划结果比较差别如下:

  1. ECS ③优化前 sql 与 RDS ③优化前 执行计划结果无很大差异,但执行结果返回的时间分别是0.47 sec 和 5.77 sec(unbelievable);
  2. ECS ③优化后 sql 与 RDS ③优化后 执行计划结果相差非常大;
    1. ECS ③优化后 sql Extra : Using where(索引);Using index, rows 最大259行等
    2. RDS ③优化后 sql Extra : 比较多Using where;Using temporary;Using filesort;Using where;Using index;Using buffer(Block Nested Loop); rows 中有172999(相当于全表查询) 

分析术语名词说明

Using index:表示MySQL将使用覆盖索引
Using where: 表示使用存储引擎检索索引在进行过滤
Using temporary: 表示MySQL对查询结果排序时会使用一个临时表
Using filesort: 表示Mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取
Using buffer(Block Nested Loop): 关联嵌套查询

分析以上结果,很明显RDS 优化后的效果非常不佳,甚至RDS优化前还差,使用时间还长; 而优化语句是按照Mysql 优化器和索引的基本原则来的,除非是唯一能想到的是两个mysql环境与配置存在差异导致的。 按照这个思路,结合RDS工单处理工程师, 去查询语句如下

  • show profiles;
  • show global variables like '%query_cache%';
  • show variables like '%optimizer_switch%' \G;
  • show create table 表明 \G;
  • show variables;

step 1:分析show profiles,发现主要耗时时间在sending data上,但无法定位,猜测可能是缓存或者是乐观锁之类的问题;

step 2:分析%query_cache%发现query_cache是没有开启的;

step 3:分析table表是否存在差异,貌似没有...排除

step 4:分析show variables;猜测rds的"tmpdir","/home/mysql/data3001/tmp",ecs自建的是| tmpdir | /tmp 会对Using temporary; Using filesort 操作有影响;怀疑/tmp 是属于内存盘,所以ECS会比RDS性能更优,但当我用df -h 看一下,发现并没有这种情况,再由RDS工程师查看ubuntu文档对其验证,发现假设不成立;

step 5: 之前是试过使用强制索引来改变优化后的sql语句的执行计划,但并没有多大的用处。RDS工程师分析认为问题出在IOPS(Input/Output Operations Per Second)上,因为RSD平均IOPS有300-400,而ECS则是0;为了排除这个原因RDS工程师很大方的建了一个1C1G RDS MySQL给我测试使用。优化后的问题不在出现,而优化前的SQL语句还是有问题:ECS的执行时间比RDS的块10多倍;

不过有一点可以确定,但重复执行多次sql语句时,执行返回结果时间会缩短,一直到一个基本固定不变的值,这说明查询存在缓存, 目前给出的解决方案是修改RDS配置如下:

set tmp_table_size=50*1024*1024*2;
set max_heap_table_size=50*1024*1024*2;
set join_buffer_size=50*1024*1024;
set sort_buffer_size=50*1024*1024;

其实,我认为这个语句无论是否有效,对RDS的用户而言都是非常差的一个表现,还需要认为的去深度考虑mysql的配置参数变量,从某种意义上说就是DB owner,那我们又何必要使用RDS呢。

后来发现 到了公司生产环境上修改配置时反而干慢了,后来一同事针对IOPS 数值不正常情况做了深度排查,发现xxxx系统上有一个定时任务,该定时任务每隔3秒执行一次,而且是针对600多万数据的非索引全表扫描,耗时已经大于3秒,(导致上一次还没执行完,变又开始下一轮的执行) ,不过定时任务用的是SpringBoot下Quartz的集成框架,其中有一共能是要等上一次任务执行完毕才可以继续下一次任务执行;这也就意味着每时每刻Mysql都有全盘扫描操作,这也是导致Mysql IOPS 居高不下的原因;

后来给出的解决方案是将该查询语句添加索引,直接让IOPS 从300-800 降到了30左右;整体性能提高;之前的条件语句优化查询也回到了正常范围;

从这点我们可以看出在Mysql中 IOPS的高低直接影响SQL 语句的性能查询与优化;

mysql性能优化分析 --- 下篇的更多相关文章

  1. mysql性能优化分析 --- 上篇

    概要 之前看过<高性能mysql>对mysql数据库有了系统化的理解,虽然没能达到精通,但有了概念,遇到问题时会有逻辑条理的分析; 问题 问题:公司xxx页面调用某个接口时,loading ...

  2. mysql性能优化-慢查询分析、优化索引和配置 (慢查询日志,explain,profile)

    mysql性能优化-慢查询分析.优化索引和配置 (慢查询日志,explain,profile) 一.优化概述 二.查询与索引优化分析 1性能瓶颈定位 Show命令 慢查询日志 explain分析查询 ...

  3. Mysql - 性能优化之子查询

    记得在做项目的时候, 听到过一句话, 尽量不要使用子查询, 那么这一篇就来看一下, 这句话是否是正确的. 那在这之前, 需要介绍一些概念性东西和mysql对语句的大致处理. 当Mysql Server ...

  4. Mysql性能优化三(分表、增量备份、还原)

    接上篇Mysql性能优化二 对表进行水平划分 如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了.如果我拆成100个表,那么每个表只有10万条记录.当然这需要数据在逻 ...

  5. mysql 性能优化方向

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  6. MySQL性能优化总结

    一.MySQL的主要适用场景 1.Web网站系统 2.日志记录系统 3.数据仓库系统 4.嵌入式系统 二.MySQL架构图: 三.MySQL存储引擎概述 1)MyISAM存储引擎 MyISAM存储引擎 ...

  7. MYSQL性能优化的最佳20+条经验

    MYSQL性能优化的最佳20+条经验 2009年11月27日 陈皓 评论 148 条评论  131,702 人阅读 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显.关于数 ...

  8. mysql 性能优化方案

    网 上有不少MySQL 性能优化方案,不过,mysql的优化同sql server相比,更为麻烦与复杂,同样的设置,在不同的环境下 ,由于内存,访问量,读写频率,数据差异等等情况,可能会出现不同的结果 ...

  9. mysql 性能优化方案1

    网 上有不少mysql 性能优化方案,不过,mysql的优化同sql server相比,更为麻烦与复杂,同样的设置,在不同的环境下 ,由于内存,访问量,读写频率,数据差异等等情况,可能会出现不同的结果 ...

随机推荐

  1. Java的基本类型和包装类型

    测试的JDK版本:java version "1.7.0_79".Java的9中基本类型:void.char.boolean.byte.short.int.long.float.d ...

  2. Arguments Optional 计算两个参数之和的 function

    创建一个计算两个参数之和的 function.如果只有一个参数,则返回一个 function,该 function 请求一个参数然后返回求和的结果. 例如,add(2, 3) 应该返回 5,而 add ...

  3. CSS3 animation 与JQ animate()的区别

    CSS3 与 JQ 根本区别 css3 animation与jQuery animate()区别在于实现机制不同 C3和JQ 完成动画的优缺点 1.css3中的过渡和animation动画都是基于cs ...

  4. ISOMAP和MDS降维

    转载自https://blog.csdn.net/victoriaw/article/details/78497316 核心:测地线距离(dijstra最短路径获得).MDS降维 Isomap(Iso ...

  5. b树和hash树的应用场景

    关系型数据库中,索引大多采用B/B+树来作为存储结构,而全文搜索引擎的索引则主要采用hash的存储结构,这两种数据结构有什么区别?       如果是等值查询,那么哈希索引明显有绝对优势,因为只需要经 ...

  6. 【CSA49G】【XSY3315】jump DP

    题目大意 有一个数轴.yww 最开始在位置 \(0\).yww 总共要跳跃很多次.每次 yww 可以往右跳 \(1\) 单位长度,或者跳到位置 \(1\). 定义位置序列为 yww 在每次跳跃之后所在 ...

  7. mysql生成20万条数据(连表插入)

    创建一个存储过程 DELIMITER $$ -- 设置定界符为$$,与';'意思相同,防止相同符号产生冲突 USE `yunkc_base1`$$ -- 使用数据库 DROP PROCEDURE IF ...

  8. pwn-GUESS

    参考了其他wp之后才慢慢做出来的 记录一下 首先checksec一下 有canary 放到IDA看下源码 运行流程大概是 有三个fork 即三次输入机会,于是无法爆破cannary 本题用的是SSP ...

  9. MFC:位图和图标的设置

    一. 图标的设置 加载图标   API函数:AfxGetApp()->LoadIconW(); 2. 显示图标 API函数:SetClassLong(); 函数原型:DWORD WINAPI S ...

  10. SQL随记(五)——函数篇

    1.SQL函数: (1)replace(String1,String2,String3):从String1字符串中找到String2,然后用String3替换String2 如:replace('ab ...