MySQL数据库告警的程序定位和优化

最近在某生产项目,甲方运维抛来一则数据库告警记录,内容大概是“[Warning] InnoDB: Cannot add field `l10_***_394` in table `tmp`.`#sql_5498_1` because after adding it, the row size is 8157 which is greater than maximum allowed size (8126) for a record on index leaf page.”,大意就是无法在表“tmp”中添加字段‘l10_***_394’,因为添加字段后,行大小为8157,将大于索引叶页上记录的最大允许大小(8126)。项目使用MySQL数据库,初步判断是EF Core生成了过大的Sql查询语句,于是开始排查解决。

一、问题分析

客户的生产环境为专用的内网,很难接触到生产机器和数据,只能先根据异常信息做远程分析和定位,大部分问题可以顺利解决,如果问题能够在开发环境复现,排查起来就很轻松了。

首先网络搜索了下解决方案,国外网络上提到此问题的较多,解决方案也很简单,只需要修改数据库的一项设置。

internal_tmp_disk_storage_engine=MyISAM

而当前系统数据库的设置则是InnoDB。

事实上在甲方客户这里是不允许修改数据库配置的,只能定位程序进行优化,当然这也是最优解,毕竟根源还是在于系统程序上。

二、异常定位

程序定位思路也比较简单,既然生产环境系统有告警记录,那先搜索一下开发环境的错误日志是否也有类似的告警。

STEP1.定位错误日志路径

STEP2.对数据库错误日志进行关键词搜索

  

果然找到了类似的告警信息,可以明确看到发生时间。

STEP3.结合系统审计流水日志,定位到这一时间调用的接口,再进一步定位到方法代码

定位到代码中的一段查询表达式程序的画风居然是这样的:

程序大概意思就是查询某个信息主表及其一系列下游子表的信息,共同展示出一组报告数据。

调试打印一下生成的查询语句,注意下左下角的滚动条,可以看到查询语句有多庞大,规模如此庞大的查询,也难怪会超出行最大限制。

三、解决方案

仔细分析整个方法代码后发现,其不仅查询了所有下游子表信息,还查询了一部分上游表信息,且后续只用到这些上游信息其中的一两个字段。

对查询表达式进行拆分和优化后,测试数据库警告消失。最后再进一步搜索日志中其它告警信息,对可优化部分逐一改进处理。

在项目开发过程中,开发人员一定要懂得写出的查询表达式最终转化成的数据库查询sql语句结构,查询语句要做最小化处理。全表查询后再自动映射的做法,写起来是很快很轻松,但却会对系统性能带来很负面的影响。

 

posted @ 2020-11-26 21:53  览岳  阅读(1417)  评论(0编辑  收藏  举报