MySQL查询速度减慢,直到重新启动

MySQL查询速度减慢,直到重新启动,mysql,database,Mysql,Database,我有一个位于MySQL 5.5数据库(INNODB)之上的服务。该服务有一个后台作业,应该每周左右运行一次。在较高级别上,后台作业执行以下操作: 在一个事务中执行一些初始数据库读写操作 在一个事务中使用一组参数执行UMQ(如下所述)。 如果没有返回记录,我们就完成了 处理来自UMQ的结果(这有点重,所以它是在任何DB之外完成的) 交易) 在一个事务中将上一步的结果写入DB(此 写入UMQ查询的表,并确保UMQ不会再次找到相同的记录) 转到第2步 UMQ-丑陋的怪物查询:这是一个令人讨厌的数据

我有一个位于MySQL 5.5数据库(INNODB)之上的服务。该服务有一个后台作业,应该每周左右运行一次。在较高级别上,后台作业执行以下操作:

  • 在一个事务中执行一些初始数据库读写操作
  • 在一个事务中使用一组参数执行UMQ(如下所述)。
    • 如果没有返回记录,我们就完成了
  • 处理来自UMQ的结果(这有点重,所以它是在任何DB之外完成的) 交易)
  • 在一个事务中将上一步的结果写入DB(此 写入UMQ查询的表,并确保UMQ不会再次找到相同的记录)
  • 转到第2步
  • UMQ-丑陋的怪物查询:这是一个令人讨厌的数据库查询,它连接一组表,在其中几个表的列上有条件,并包含一个不存在的子查询,其中包含一些更多的连接和条件。UMQ包括订单,但也有1000个限制。尽管查询很糟糕,但我已经在这里做了我所能做的——在所有过滤的列上都有索引,连接都在外键关系上

    我确实希望UMQ很重,需要一些时间,这就是为什么它在后台作业中执行。然而,我看到的是性能迅速下降,直到它最终导致我的服务超时(10次迭代后可能慢50倍)


    首先,我认为这是因为UMQ查询的数据发生了变化(请参见上面的步骤4),但事实并非如此,因为如果我从慢速查询日志中获取最后一个查询(导致超时的查询),并直接执行它,我只会得到相同的行为,直到我重述MySQL服务。重新启动后,对完全相同的数据进行的精确查询(重新启动前花费的时间>30秒,现在花费的时间)表明,我看到的行为是MySQL优化器如何使用InnoDB统计信息来决定执行计划的结果。让我走上正确的轨道(即使它没有确切地讨论我的问题)。从中我学到的最重要的一点是MySQL在启动时计算统计数据,然后每隔一段时间计算一次。然后使用此统计信息优化查询

    按照我设置测试数据的方式,表T中的大多数写入操作都是在步骤4中完成的,开始时是空的。每次迭代后,T将包含越来越多的记录,但InnoDB统计数据尚未更新以反映这一点。正因为如此,MySQL优化器总是为UMQ选择一个执行计划(其中包括一个与T的连接),该计划在T为空时运行良好,但越是包含越多的记录T就越糟糕

    为了验证这一点,我添加了一个分析表T;在每次执行UMQ之前,快速退化消失。无闪电性能,但可接受。我还看到,离开数据库半小时左右(可能会短一点,但至少会超过几分钟)将允许InnoDB统计数据自动刷新


    在一个真实的场景中,UMQ中涉及的表的索引基数的相对差异看起来会非常不同,并且变化不会那么快,因此我决定我真的不需要对此做任何事情。

    非常感谢您的分析和回答。在mariadb 10.1和bacula服务器9.4(debian buster)上的ci期间,我已经搜索这个问题好几天了

    情况是,在CI周期中安装了fresh server之后,前两个测试(备份和恢复)在未启动的mariadb服务器上顺利运行,只有第三个测试表明一个特定的UMQ大约需要20分钟(在恢复过程中从约30k行的表中构建目录树)


    除非重新启动mardiadb服务器或分析表,否则问题不会消失<代码>分析表或重新启动更改了字段的基数和内部查询处理,正如链接文章中所述。

    您可以使用运行查询吗?是否关闭事务?有限制的查询是否在每个循环中使用递增的偏移量?@Michael Mior:好主意-我将玩一玩分析,并用我的发现更新问题。@Darhazer:是的,我已经非常仔细地检查了我是否提交了事务。通过检查我的应用程序代码和MySQL常规日志。不,不使用递增偏移量-是被查询的数据以这样的方式被更改,以至于在下一次迭代中找不到它。