为什么查询有时挂起而其他人挂起

时间:2013-06-29 23:25:18

标签: mysql

在我支持的遗留产品中,有一个对mysql的PHP查询,它有时会起作用,而在其他时候会挂起(可能是有限的,但如果是这样,则持续时间不合理)。我的SQL技能非常有限,但我能够在mysql上手动运行查询,这是我到目前为止所发现的。

给定表'orders','lineItems'和'lineItemDefns',

其中每个订单都是一对多的lineItems和 lineItems与lineItemDefinitions一对一

和表OrderReports将每个报告(reportId)映射到一组订单及其lineItem数据和以下SQl查询:

SELECT SEC_TO_TIME(SUM(orders.itemCount*lineItems.itemCount*lineItemDefns.estimatedDuration)) as estimatedTotalDuration
FROM orders, lineItems, lineItemDefns
WHERE orders.id=lineItems.parentOrder
  AND lineItemDefns.id=lineItems.definitionId
  AND orders.id in 
      (SELECT DISTINCT orderId 
       FROM OrderReports
       WHERE OrderReports.reportId=98619);

(这是在用PHP调用DBI getAll之前立即从查询字符串中转储的。)

当我单独运行第二个选择时,它几乎立即返回一行。当我运行第一个select而将orderId替换为第二个select时,它会在不到一秒的时间内返回NULL的estimatedTotalDuration。此reportId只有两行,对应于此订单的两个lineItem行。 lineItems(在lineItemDefns中)的estimatedDurations都是NULL。

查询中的所有ID(主要和外来)都被编入索引。

所有数字都是整数,持续时间以秒为单位(int(11))。在这种情况下,itemCounts为1。

但是,当我按上述方式运行时,它可以在我的测试数据库中运行(在30秒内很慢),但是当生产数据的等效报告停留了不合理的时间(超过50分钟)时,它将无法完成

似乎没有表被锁定,因为我可以在报告挂起时运行前两个部分查询测试。

有人可以指出任何明显的原因(例如处理null estimatedDurations?)。 同样,任何关于下一步要看什么的提示?它是一个生产数据库,因此我不想做任何可能导致其他用户延迟的事情。

任何重写查询的建议也会受到赞赏。

Fedora 7上的mysql 5.0.37(测试数据库是Fedora 8上的mysql 5.0.45)

像大爆炸理论中的便士一样,这就是我所知道的。哦,Fig Newton以马萨诸塞州牛顿命名。 ;)

1 个答案:

答案 0 :(得分:1)

问题是旧版本的MySQL没有很好地使用子查询优化in。特别是,它为每个可能的输出行运行子查询。 。 。一遍又一遍地做select distinct

您可以将此子查询移动到from子句以解决问题:

SELECT SEC_TO_TIME(SUM(orders.itemCount*lineItems.itemCount*lineItemDefns.estimatedDuration)) as estimatedTotalDuration
FROM orders join
     lineItems
     on orders.id=lineItems.parentOrder join
     lineItemDefns
     on lineItemDefns.id=lineItems.definitionId join
     (SELECT DISTINCT orderId 
      FROM OrderReports
      WHERE OrderReports.reportId=98619
     ) orep
     on orders.id = orep.id

我还将所有连接移动到from子句中以使用标准ANSI连接语法。