3

我有一个T-SQL查询性能非常差,以至于超时。罪魁祸首是这两个带有嵌入式查询的嵌套 CASE 语句:

SELECT
  CASE
    WHEN b.month_type = (CASE
        WHEN dbo.CURRENT_BUSINESSDAY(GETDATE()) >= 8 THEN 'Current Month BD2'
        ELSE (CASE
            WHEN dbo.CURRENT_BUSINESSDAY(GETDATE()) < 8 AND
              (SELECT
                MAX(b.cal_start_date)
              FROM factbillingcollectionhistory a
              JOIN dimdateperiod b
                ON a.fiscal_month = b.fsc_period)
              <> (SELECT
                MAX(cal_start_date)
              FROM dimdateperiod) THEN 'Current Reporting Month'
            ELSE 'Current Month BD2'
          END)
      END) THEN a.BILLINGS_BUDGET
    ELSE 0
  END
  AS BILLINGS_BUDGET,
  CASE
    WHEN b.month_type = (CASE
        WHEN dbo.CURRENT_BUSINESSDAY(GETDATE()) >= 8 THEN 'Current Month BD2'
        ELSE (CASE
            WHEN dbo.CURRENT_BUSINESSDAY(GETDATE()) < 8 AND
              (SELECT
                MAX(b.cal_start_date)
              FROM factbillingcollectionhistory a
              JOIN dimdateperiod b
                ON a.fiscal_month = b.fsc_period)
              <> (SELECT
                MAX(cal_start_date)
              FROM dimdateperiod) THEN 'Current Reporting Month'
            ELSE 'Current Month BD2'
          END)
      END) THEN a.COLLECTION_GOALS
    ELSE 0
  END
  AS COLLECTION_GOALS

CURRENT_BUSINESSDAY函数的作用正是它所描述的......标识报告期间的当前工作日。

的逻辑CASE是根据我们在报告周期中的位置以及我们是否收到更新的目标文件来返回目标值。如果还不是 BD8,请检查我们是否收到了新文件(通过比较最大日期)。如果我们收到了,则将该值返回到报告中,否则返回上个月的值。如果它在 BD8 之后并且我们仍然没有新文件,它应该返回“0”,这将使我们的过程失败并让我们知道他们没有按时提供数据。

是否有更有效的方法来编写此逻辑以防止查询超时?请记住,此脚本用于在表格模型中构建表格,因此只有 SELECT 起作用……没有变量声明或任何类似的东西。

想法?

4

1 回答 1

1

由于 COLLECTION_GOALS 和 BILLINGS_BUDGET 中的案例逻辑相同,我建议将逻辑移出内联子查询并进入主 FROM 子句,如下所示:

SELECT CASE WHEN b.month_type = z.month_type
           THEN a.BILLINGS_BUDGET
           ELSE 0
       END AS BILLINGS_BUDGET,
       CASE WHEN b.month_type = z.month_type
           THEN a.COLLECTION_GOALS
           ELSE 0
       END AS COLLECTION_GOALS
FROM (SELECT CASE WHEN dbo.CURRENT_BUSINESSDAY(GETDATE()) >= 8
                 THEN 'Current Month BD2'
                 ELSE (CASE WHEN dbo.CURRENT_BUSINESSDAY(GETDATE()) < 8 AND 
                                 (SELECT max(b.cal_start_date) 
                                         FROM factbillingcollectionhistory a
                                         JOIN dimdateperiod b
                                           ON a.fiscal_month = b.fsc_period) <> (SELECT max(cal_start_date) FROM dimdateperiod)
                           THEN 'Current Reporting Month'
                           ELSE 'Current Month BD2'
                       END)
             END month_type) z
CROSS JOIN
/*... Rest of query */

这应该导致它在每个查询中被评估一次,而不是对查询返回的每一行进行两次评估。

于 2015-05-13T15:41:32.640 回答