【问题标题】:Calculated fields from queries in CTE are quite slow, how to optimizeCTE中查询的计算字段很慢,如何优化
【发布时间】:2015-10-28 12:28:11
【问题描述】:

我有一个包含计算字段的查询,其中涉及在 CTE 中为每个字段查找数据集,但是当我找到其中几个字段时,速度很慢。

这是一个想法:

;WITH TRNCTE AS
(
    SELECT TRN.PORT_N, TRN.TRADE_DATE, TRN.TRANS_TYPE, TRN.TRANS_SUB_CODE, TRN.SEC_TYPE, TRN.SETTLE_DATE 
    FROM TRNS_RPT TRN
    WHERE TRN.TRADEDT >= '2014-01-01' AND TRN.TRADEDT <= '2014-12-31'    
)

SELECT
    C.CLIENT_NAME,
    C.PORT_N,
    C.PHONE_NUMBER,
    CASE
        WHEN EXISTS(SELECT TOP 1 1 FROM TRNCTE WHERE PORT_N = C.PORT_N AND MONTH(SETTLE_DATE) = 12) THEN 'DECEMBER TRANSACTION'
        ELSE 'NOT DECEMBER TRANSACTION'
    END AS ALIAS1
FROM CLIENTS C
WHERE EXISTS(SELECT TOP 1 1 FROM TRNCTE WHERE PORT_N = C.PORT_N)

如果我有许多这样的计算字段,则执行查询最多可能需要 10 分钟。在 CTE 中收集大约 1,000,000 条记录的数据大约需要 15 秒。

我真的不需要 JOIN,因为我并没有真正使用 JOIN 会执行的数据,我只想检查 TRNS_RPT 中是否存在具有某些条件的记录,并将别名字段设置为某些值我是否找到这样的记录与否。

你能帮我优化一下吗?谢谢

【问题讨论】:

  • 你的意图是什么?你想看看在 12 月有交易的客户吗?
  • CTE 将对主查询中的每个引用“执行”一次。结果不会被缓存和重用。
  • @PeterRing 否。意图就是如图所示。如果我有一个交易符合某个客户的某些条件,那么某些标志(别名)将具有不同的值。

标签: sql sql-server-2005 common-table-expression


【解决方案1】:

在这种情况下你可以做一个小技巧。您需要将 cte 的结果插入到临时表中。这样,您将节省重新计算的成本。 请试一试。

;WITH TRNCTE AS
    (
        SELECT TRN.PORT_N, TRN.TRADE_DATE, TRN.TRANS_TYPE, TRN.TRANS_SUB_CODE, TRN.SEC_TYPE, TRN.SETTLE_DATE 
        FROM TRNS_RPT TRN
        WHERE TRN.TRADEDT >= '2014-01-01' AND TRN.TRADEDT <= '2014-12-31'    
    )
SELECT * INTO #temp
FROM TRNCTE

    SELECT
        C.CLIENT_NAME,
        C.PORT_N,
        C.PHONE_NUMBER,
        CASE
        WHEN EXISTS(SELECT TOP 1 1 FROM #temp WHERE PORT_N = C.PORT_N AND MONTH(SETTLE_DATE) = 12) THEN 'DECEMBER TRANSACTION'
        ELSE 'NOT DECEMBER TRANSACTION'
    END AS ALIAS1
    FROM CLIENTS C
    WHERE EXISTS(SELECT TOP 1 1 FROM #temp WHERE PORT_N = C.PORT_N)

DROP TABLE #temp

【讨论】:

    【解决方案2】:

    通过查看您的代码,我可能会使用join 来避免在查询中两次包含TRNCTE。如果TRNCTE.PORT_N 不是唯一的,则不完全相同,您会得到重复的行。

    ;WITH TRNCTE AS
    (
        SELECT TRN.PORT_N, TRN.TRADE_DATE, TRN.TRANS_TYPE, TRN.TRANS_SUB_CODE, TRN.SEC_TYPE, TRN.SETTLE_DATE 
        FROM TRNS_RPT TRN
        WHERE TRN.TRADEDT >= '2014-01-01' AND TRN.TRADEDT <= '2014-12-31'    
    )
    SELECT
        C.CLIENT_NAME,
        C.PORT_N,
        C.PHONE_NUMBER,
        CASE
            WHEN MONTH(TRNCTE.SETTLE_DATE) = 12) 
            THEN 'DECEMBER TRANSACTION'
            ELSE 'NOT DECEMBER TRANSACTION'
        END AS ALIAS1
    FROM CLIENTS C
    JOIN TRNCTE ON C.PORT_N = TRNCTE.PORT_N
    

    【讨论】:

    • 遗憾的是,这将给出与原始结果不同的结果。原件将显示客户在 12 月是否有交易。如果客户有多个交易,您的解决方案将多次显示客户。
    • @PeterRing 是的,如我的回答中所述。
    猜你喜欢
    • 2014-02-05
    • 2023-02-26
    • 2021-12-12
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多