MySQL简单INSERT超慢原因排查

 导 读

作者:高鹏(重庆八怪)

原文地址:

https://www.jianshu.com/p/5248ca67eac2

这个问题是来自一位朋友@春波,我通过pstack最终确认问题,涉及到两个参数的设置,我将从源码进行解释,如果有误还请见谅。

一、问题展示

1、简单插入需要1秒

语句截图如下:

640?wx_fmt=png

耗时截图如下:

640?wx_fmt=jpeg


2、profile展示:

640?wx_fmt=jpeg

实际上这里的query end是一个非常有用的信息,基本确认是在order_commit函数上的等待。

二、问题初次分析

在我遇到的案例中有大事务造成的小事务commit慢的情况,且状态也是query end,但是这里问题显然不太一样,如果是大事务造成的会是偶尔出现commit慢的情况而这里是稳定出现等待1秒的情况。但是我还是要朋友采集了binlog的大事务信息使用我的一个工具如下:

640?wx_fmt=png

这个工具是我用C写的不依赖其他工具解析binlog获取有用信息的工具,也很多朋友在用。占时没有开源,其实也很简单就是分析binlog的event来获取有用信息。

得到的简化结果如下:

-------------Now begin--------------
Check Mysql Version is:5.7.19-log
Check Mysql binlog format ver is:V4
Warning:Check This binlog is not closed!
Check This binlog total size:87546667(bytes)
Note:load data infile not check!
-------------Total now--------------
Trx total[counts]:42771
Event total[counts]:251792
Max trx event size:9268(bytes) Pos:78378238[0X4ABF4FE]
Avg binlog size(/sec):16745.729(bytes)[16.353(kb)]
Avg binlog size(/min):1004743.688(bytes)[981.195(kb)]
...
--Large than 2000000(bytes) trx:
(1)Trx_size:54586527(bytes)[53307.156(kb)] trx_begin_p:359790[0X57D6E] trx_end_p:54946317[0X3466A0D]
Total large trx count size(kb):#53307.156(kb)
....
---(79)Current Table:froad_cbank_anhui.cb_sms_log::
   Insert:binlog size(824224(Bytes)) times(3135)
   Update:binlog size(2046042(Bytes)) times(3841)
   Delete:binlog size(0(Bytes)) times(0)
   Total:binlog size(2870266(Bytes)) times(6976)
---(80)Current Table:test.2018products::
   Insert:binlog size(54586359(Bytes)) times(6647)
   Update:binlog size(0(Bytes)) times(0)
   Delete:binlog size(0(Bytes)) times(0)
   Total:binlog size(54586359(Bytes)) times(6647)
---Total binlog dml event size:73212228(Bytes) times(65090)

实际上我们很容易看到binlog整个才80M左右确实包含一个大事务如下,大约占用了50M多。

--Large than 2000000(bytes) trx:
(1)Trx_size:54586527(bytes)[53307.156(kb)] trx_begin_p:359790[0X57D6E] trx_end_p:54946317[0X3466A0D]
Total large trx count size(kb):#53307.156(kb)

但是大事务只会在提交的那一刻影响其他事务的提交且状态为query end参考我早期的一篇文章http://blog.itpub.net/7728585/viewspace-2133674/

我们先排除大事务导致的的问题。那么到底是什么问题呢,有朋友说可能是半同步,但是不使用半同步的情况下也一样。且我觉得半同步的导致慢的状态应该不是query end 占时没有测试。

三、确认问题

没有办法只能使用pstack进行分析,幸运的是这个问题确实简单如下的pstack栈帧:

640?wx_fmt=png


显然我的猜测没有问题确实是ordered_commit上出的问题,直接打开源码找到如下:

640?wx_fmt=png


这段代码位于flush阶段之后 sync阶段之前,目的在于通过人为的设置delay来加大整个group commit组的事务数量,从而减少进行磁盘刷盘sync的次数。这块代码虽然以前看过但是没用过这两个参数也就直接跳过了。

四、stage_manager.wait_count_or_timeout函数分析和参数分析

这个函数还是非常简单如下逻辑 看注释即可:

void Stage_manager::wait_count_or_timeout(ulong count, ulong usec, StageID stage)
{
  ulong to_wait=
    DBUG_EVALUATE_IF("bgc_set_infinite_delay", LONG_MAX, usec);
  /*
    For testing purposes while waiting for inifinity
    to arrive, we keep checking the queue size at regular,
    small intervals. Otherwise, waiting 0.1 * infinite
    is too long.
   */
  ulong delta=
    DBUG_EVALUATE_IF("bgc_set_infinite_delay", 100000, //此处将等待时间分割 将使用 
                     max<ulong>(1, (to_wait * 0.1)));  //binlog_group_commit_sync_delay*0.1 和 1之间的 大的那个值作为时间分割 (单位 1/1000000 秒)
                                                       //binlog_group_commit_sync_delay是 (1000000)1秒则时间分割为0.1s(100000)
  while (to_wait > 0 && (count == 0 || static_cast<ulong>(m_queue[stage].get_size()) < count)) //进行主体循环退出条件为 1、binlog_group_commit_sync_delay设置的时间消耗完
  {                                                                                             //2本组事务数量>binlog_group_commit_sync_no_delay_count 
    my_sleep(delta);//每次休眠delta时间如果是1秒则每次休眠0.1秒
    to_wait -= delta;//进行总时间-delta 时间 
  }
}

从源码我们分析一下参数binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count的含义:

  • binlog_group_commit_sync_delay:通过人为的设置delay来加大整个group commit组的事务数量,从而减少进行磁盘刷盘sync的次数,但是受到binlog_group_commit_sync_no_delay_count的限制,单位1/1000000秒。最大值1000000也就是1秒

  • binlog_group_commit_sync_no_delay_count:如果delay的时间内如果group commit中的事务数量达到了这个设置就直接跳出等待,而不需要等待binlog_group_commit_sync_delay的时间,单位group commit中事务的数量。

举个列子比如我binlog_group_commit_sync_delay设置为10,binlog_group_commit_sync_no_delay_count设置为10,整个group commit将在这里等待,达到2个条件中的1个将会退出等待:

  • 等待达到了1/100000 秒

  • group commit中事务数量达到了10

四、问题库设置

最后叫朋友查看了他们库的设置如下:

640?wx_fmt=png


居然binlog_group_commit_sync_delay设置为了最大值1000000也就是1秒,这也就解释了为什么简单的insert都会等待1秒了,且状态为query end。

五、总结

  • 整个问题的排除最终还是依赖的pstack,这也再一次体现了它的重要性。栈帧是不会骗人的只有不懂的

  • 要对query end代表的什么比较清楚

  • 至此我知道了2种query end(或者显示commit为starting)状态下小事务提交慢的可能
    1、某个大事务提交引起偶尔的提交慢
    2、binlog_group_commit_sync_delay和binlog_group_commit_sync_no_delay_count 设置不正确引起提交慢


对本文有任何疑问可扫码添加原文作者微信

640?wx_fmt=jpeg


640?wx_fmt=gif


640?wx_fmt=gif


加入QQ技术交流群

扫码加入知数堂4群-王者峡谷

(QQ群号:650149401)

      

640?wx_fmt=png

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
根据引用中的解释,方案二中的子查询在MySQL中会被自动优化成直接的左连接,因此在执行explain命令时并没有出现差异。然而,在子查询中加入了having子句后,MySQL无法自动优化成直接的左连接,因此按照SQL语句的调用顺序执行,导致explain结果中出现了一个额外的子查询行。这样实现了原本的目的,即从10,000 x 10,000 x 10,000的复杂度降低到10,000 x 10,000的复杂度,从而提升了速度。 根据引用中的方案二的描述,通过将两次左连接合并为一次来减少笛卡尔积的操作,可以显著提升速度。具体的SQL结构如下: ``` select p.id,p.name,pss.sort from table1 p left join ( select name,sort from table2 ps left join table2 ps2 on ps.name = ps2.name and ... where ... ) pss on p.name = pss.name where ... order by pss.sort asc,p.sale desc,p.time desc limit 0,10 ``` 而引用中提到的第三种解决方案是将SQL语句拆分开来,因为是左连接,关联关系可以分开执行,然后逐个执行,观察执行情况。 因此,根据以上三个引用的内容,可以得出解决MySQL左连接特别的三种方法,即通过优化子查询、合并左连接操作和拆分SQL语句来提升速度。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [mysql 优化复杂sql (多个left join 数量过大 order by 巨)](https://blog.csdn.net/qq_40835969/article/details/128239398)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [mysql left join 查询的问题排查](https://blog.csdn.net/tianjiliuhen/article/details/127446340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值