特定于服务器的超慢SQL更新命令

时间:2015-03-11 14:19:57

标签: mysql sql performance

我在MySQL 5.5.31上有一个运行以下更新的MYISAM数据库

UPDATE tableA AS a
INNER JOIN tableB AS b
ON((a.id = b.dnum and a.account = b.account) 
   OR a.id = CONCAT(b.dnum, '\_', b.account, '\_', b.unique))
SET a.status = 0, a.apd = NULL WHERE a.status = 1;

我尝试使用相同的数据集和几乎相同的mysql设置在3台不同的测试计算机上运行此查询,并且查询在1秒或更短的时间内完成,更新大约25000行。

在生产服务器上运行此查询并且它永远不会完成,我已经在40多分钟后将其杀死了。

测试盒和生产之间配置的主要区别是MySQL版本5.5.41,生产系统有复制日志,所有缓存大小等都相同。

我找到了一个可以运行select并创建25000+更新语句的工作,这个过程可以在2-3秒内完成生产。但是,我担心生产的SQL性能与测试环境完全不同,因此在意外的地方可能会发生非常慢的性能问题。

我在生产服务器上创建了一个新的测试数据库并将数据导入到它中,它具有相同的可怕性能,因此它似乎特定于此服务器的配置。一般来说,SQL性能似乎很好,到目前为止,这是唯一一个在性能方面明显不同的查询。

我认为原因可能是复制,它被设置为行级别,因此需要在bin日志中生成几千行更新,但我添加了 SET @@ session.sql_log_bin = 0 ; SET @@ session.sql_log_bin = 1; 新测试数据库上SQL的任一侧,它似乎没有什么区别。我还配置了一个测试盒来写入bin日志(但没有设置一个slave),这对性能没有太大的影响。

有没有人知道如何确定此数据库在合理级别执行此查询的任何可能原因,或任何诊断以找出正在发生的事情?

2 个答案:

答案 0 :(得分:2)

or中的join条件很慢。我建议将其分为两个更新:

UPDATE tableA a INNER JOIN
       tableB b
       ON a.id = b.dnum and a.account = b.account
    SET a.status = 0,
    a.apd = NULL
    WHERE a.status = 1;

UPDATE tableA a INNER JOIN
       tableB b
       ON a.id = CONCAT(b.dnum, '\_', b.account, '\_', b.unique))
    SET a.status = 0, a.apd = NULL
    WHERE a.status = 1;

然后,您可以使用适当的索引加速这些速度。第一个tableA(status, id, account)tableB(dnum, account)。第二个tableA(id, status)

答案 1 :(得分:0)

找到性能差异的原因。

所有测试服务器的默认max_seeks_for_key设置为18446744073709551615,但生产服务器上的问题设置为500.当我分析服务器之间的细微差别时,这种差异并没有突出,因为我假设这个设置可能会提高性能而不是降低性能。