T-SQL 替代嵌套 CASE 以获得更好的性能?
T-SQL alternatives to nested CASE for better performance?
我有一个 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
的逻辑是 return 目标值基于我们在报告周期中所处的位置以及我们是否收到更新的目标文件。如果还不是 BD8,请检查我们是否收到了新文件(通过比较最大日期)。如果我们收到了它,return 报告该值,否则 return 前一个月的值。如果在 BD8 之后我们仍然没有新文件,它应该 return "0" 这将使我们的过程失败并让我们知道他们没有按时提供数据。
是否有更有效的方法来编写此逻辑的脚本以防止查询超时?请记住,此脚本用于在表格模型中构建 table,因此只有 SELECT 在起作用……没有变量声明或任何类似的东西。
想法?
由于 COLLECTION_GOALS 和 BILLINGS_BUDGET 中的 case 逻辑相同,我建议将逻辑移出内联子查询并移至主 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 */
这应该会导致每个查询对其进行一次评估,而不是对查询返回的每一行进行两次评估。
我有一个 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
的逻辑是 return 目标值基于我们在报告周期中所处的位置以及我们是否收到更新的目标文件。如果还不是 BD8,请检查我们是否收到了新文件(通过比较最大日期)。如果我们收到了它,return 报告该值,否则 return 前一个月的值。如果在 BD8 之后我们仍然没有新文件,它应该 return "0" 这将使我们的过程失败并让我们知道他们没有按时提供数据。
是否有更有效的方法来编写此逻辑的脚本以防止查询超时?请记住,此脚本用于在表格模型中构建 table,因此只有 SELECT 在起作用……没有变量声明或任何类似的东西。
想法?
由于 COLLECTION_GOALS 和 BILLINGS_BUDGET 中的 case 逻辑相同,我建议将逻辑移出内联子查询并移至主 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 */
这应该会导致每个查询对其进行一次评估,而不是对查询返回的每一行进行两次评估。