3

在我支持的旧产品中,有一个对 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 之前从查询字符串中转储的。)

当我自己运行第二个选择时,它几乎立即返回一行。当我运行第一个选择时,将该 orderId 替换为第二个选择,它会在不到一秒的时间内返回一个 NULL 的估计总持续时间。这个reportId只有两行,对应这个订单的两个lineItem行。lineItems(在 lineItemDefns 中)的estimatedDurations 都是NULL。

查询中的所有 id,主要的和外部的,都被索引。

所有数字都是整数,持续时间以秒为单位 (int(11))。本例中的 itemCounts 为 1。

但是,当我按上述方式运行它时,它可以在我的测试数据库中运行(在 30 秒时很慢),但是当离开不合理的时间(超过 50 分钟)以获得生产数据的等效报告时,它不会完成。

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

有人可以指出任何明显的原因(例如处理空的估计持续时间?)。同样,关于接下来要看什么的任何提示?这是一个生产数据库,所以我不想做任何可能导致其他用户延迟的事情。

任何重写查询的建议也将不胜感激。

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

就像,生活大爆炸中的佩妮,这就是我所知道的。哦,无花果牛顿是以马萨诸塞州牛顿命名的。;)

4

1 回答 1

1

问题是旧版本的 MySQL 没有很好地优化in子查询。特别是,它为每一个可能的 output 行运行子查询。. . 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 联接语法。

于 2013-06-29T23:35:19.397 回答