3

我遇到了一个小问题,

这是一个演示查询

select 
    A.order_id, 
    if(
         A.production_date != '0000-00-00', 
         A.production_date,
         if(
              SOME INNER QUERY != '0000-00-00', 
              SOME INNER QUERY ,
              SOME OTHER INNER QUERY
           )
    ) as production_start_date
from
    orders A

所以基本上,假设SOME INNER QUERY需要 10 秒来进行计算,从 8 个不同的表中获取数据,检查相同订单类型的过去历史记录等,如果结果是日期,我会在第一个条件下获取该日期。但是现在计算if条件需要20秒,10秒,重新执行返回结果需要10秒。

有什么办法可以减少这种情况吗?

如果有人有兴趣查看实际查询http://pastebin.com/zqzbpEei

4

1 回答 1

1

假设您的查询看起来像这样(抱歉,我放弃了尝试定位实际查询):

IF(
    (SELECT aField FROM aTable WHERE bigCondition) != '0000-00-00',
    SELECT aField FROM aTable WHERE bigCondition,
    SELECT anotherField FROM anotherTable
)

你可以改写如下:

SELECT IF (
    someField != '0000-00-00',
    someField,
    SELECT anotherField FROM anotherTable
)
FROM aTable WHERE bigCondition

这样你bigCondition只计算一次。


这个查询确实很丑陋。

您的主要问题似乎是IF()构造的滥用(和滥用,大时间)。它应该保留给简单的条件和操作。这同样适用于逻辑运算符。不要对整个查询进行操作。例如,我看到这一点在您的查询中出现了几次:

IF(
    (SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id) IS NULL
       OR (SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id) = '',
    '6', -- by the way, why is this a string?! This is an integer, isn't it?
    (SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id)
)

这是不好的。条件应直接移入SELECT。改写如下:

SELECT
    IF (v1.weekends IS NULL OR v1.weekends = '', 6, v1.weekends)
FROM vendor v1 WHERE v1.vendor_id = A.vendor_id

那是两个SELECT得救了。对包含查询的每一个都执行此IF()操作,我敢打赌,您将把查询速度提高几个数量级。

关于您当前的代码还有很多话要说。不幸的是,您可能需要重构 ORM 的某些部分。向某些类添加新的、更专业的方法,并使它们使用您手动制作的新查询。然后重构您当前的操作,以便它使用这些新方法。

于 2013-07-25T21:32:11.497 回答