MySQL:故障疑问等4例


简单记录,仅供参考。


一、slow log记录到表导致的故障

5.7.22版本

问题:

大概问题就是,数据库crash 过后,有一个线程CPU很高,执行show processlist等语句,都是第一次可以执行,而第二次就不能执行了,等待如下。

image.png

其他线程CPU不高。

分析:

对于类似问题,很显然是耗用CPU的线程正在处理某种工作,这种工作可能到堵塞了其他session。这种场景适合用pstack进行分析,因为反正都卡主了,也无所谓。

当然PSTACK,很容易就看出了在干什么如下:

  • 耗用CPU的线程:这个线程记录慢查询到slow_log,发现需要修复,正在对slow_log 这个表进行修复,具体是CSV引擎,我们也不过多关注了如下:


    image.png
  • 其他等待的线程:


    image.png

其他session如果也想记录slow_log,那么需要先open 表获取MDL LOCK。很显然由于正在对slow_log进行修复,这个过程可能由于slow_log巨大而非常慢,这个过程持有了MDL LOCK(独占),因此出现waiting for table metadata lock的等待,这也是正常的。

为什么能执行一次,第二次就不能执行了?

上面我们看到了执行语句第一次是可以执行的,只是第二次卡主了。这个问题主要是,记录慢查询的时候,实际上语句已经执行完成了,并且客户端已经接收到了Result Set报文,客户端看来语句执行结束了,但是这个session(线程)还在跑记录慢查询接口,实际上已经卡主了。

当再次客户端发送COM_QUERY 报文给MySQLD的时候,当然这个线程就不能读取到命令。

上面的show processlist虽然显示等待为waiting for table metadata lock,但是这个等待是等待在slow_log这个table上的,查询的结果已经发送结果给客户端了。

大概就是这个意思,如下:

 服务端线程                   客户端      
                            发起查询请求   
接收客户端语句
执行语句
发送结果给客户端
                            获取结果语句结束 
记录慢查询堵塞(MDL LOCK)

                            再次执行语句
无法响应      

这个小案例也说明,我们还是不要使用表来记录慢查询吧。

二、8.0.26 - 8.0.28 MySQL DUMP的一个小BUG

当我们使用mysqldump --master-data > sql.sql 这种方式备份的时候,在8.0.26和8.0.28之前有一个小BUG,就是master-data 已经成为了警告,需要使用source-data进行代替,如果不代替,出现的警告会写入到stdout中,然后被重定向到sql.sql中。当然一般的错误和警告还是写到stderr。

当进行恢复的时候就会出现报错,这个小BUG在8.0.30进行了修复如下:

Deprecation warnings returned to client programs were sent to stdout rather than stderr, which in the case of mysqldump could mean that the dump file no longer worked because the warnings were included in it. The issue has now been fixed and the warnings are sent to stderr. (Bug #104769, Bug #33733529)

所以如果是这几个版本最好用source-data来代替master-data

三、慢查询中的lock_time和performance中SUM_LOCK_TIME的区别

很早以前就注意过这个SUM_LOCK_TIME,当时测试没啥用,就没管了,最近稍微看了一下,为什么没用。如下。

慢查询的lock_time

来自于2个函数

  • A:THD::set_time_after_lock:mysql_lock_tables 后设置,MDL LOCK获取之后,流程到这里的时候设置utime_after_lock
  • B:thd_storage_lock_wait:引擎层设置lock time,也就是在innodb行被堵塞后设置也就是在原有的utime_after_lock基础上加上锁等待的时间

慢查询记录lock time时候用使用

(A+B)- start_time:因此一般lock time包含了MDL LOCK和row lock的时间,当然不完全相等,因为A是一个流程值。

performance中的SUM_LOCK_TIME

和lock time的不同在于其只包含了A,也就是时间是 A - start_time,也就是去掉引擎层的等待时间,innodb就是row lock,其来源也是THD::set_time_after_lock打开看就明白了。

mysql_lock_tables
 ->THD::set_time_after_lock
   ->pfs_set_statement_lock_time_v2
     ->inline_mysql_set_statement_lock_time 

四、MySQL 8.0中的迭代器

在MySQL 8.0中出现了很多的迭代器,比如:

  • RefIterator:索引定位相关的迭代器
  • FilterIterator:where条件相关的迭代器
  • TableRowIterator:扫描一行数据的迭代器
  • HashJoinIterator:hash join的迭代器
  • NestedLoopIterator:nest loop join的迭代器

当然还有很多很多的迭代器,它们有一个统一的父类RowIterator,比如FilterIterator迭代器,


image.png

最近在找where条件过滤的时候,我去找了一阵子,比如如下语句:

select * from tab where a=1;

如果走全表扫描实际上就是FilterIterator迭代器套TableRowIterator迭代器,先通过全表扫描,拿到一行数据,然后通过FilterIterator去过滤这个where条件。这个和5.7完全不同了。大概就是这个意思,

image.png

而5.7的where条件过滤是这样的:


image.png

很是不一样,统一的抽象更加标准化了,不能说不同,那是完成全不同啊。

你可能感兴趣的:(MySQL:故障疑问等4例)