Joining CTEs Causing Performance Issues

  • Hi everyone

    I am not sure why the query is taking so long to run.  If I run each CTE separately then it runs in less than 2 seconds.  However, when I join them they take forever to run.  I stop the query after about 10 minutes.  I am pretty sure I am joining them incorrectly.  What am I doing wrong?

    Below is code:

    ALTER PROCEDURE [dbo].[QueryStockData]
    AS

    TRUNCATE TABLE DBO.StockData;

    WITH CTE1
    AS
    (
    SELECTT1.SYMBOL, CONVERT(DATE, T1.DATE_DATETIME) AS TRADE_DATE, SUM(T1.FIELD1 * T1.FIELD2) AS VALUE1
    FROMdbo.StockDB AS T1
    WHERET1.FIELD2 = T1.FIELD3 AND T1.TYPE = 'A'
    GROUP BYT1.SYMBOL, CONVERT(DATE, T1.DATE_DATETIME)
    ),

    CTE2
    AS
    (
    SELECTT2.SYMBOL, CONVERT(DATE, T2.DATE_DATETIME) AS TRADE_DATE, SUM(T2.FIELD1 * T2.FIELD2) AS VALUE2
    FROMdbo.StockDB AS T2
    WHERET2.FIELD2 = T2.FIELD4 AND T2.TYPE = 'B'
    GROUP BYT2.SYMBOL, CONVERT(DATE, T2.DATE_DATETIME)
    ),

    CTE3
    AS
    (
    SELECTT3.SYMBOL, CONVERT(DATE, T3.DATE_DATETIME) AS TRADE_DATE, SUM(T3.FIELD1 * T3.FIELD2) AS VALUE3
    FROMdbo.StockDB AS T3
    WHERET3.FIELD2 = T3.FIELD3 AND T3.TYPE = 'C'
    GROUP BYT3.SYMBOL, CONVERT(DATE, T3.DATE_DATETIME)
    ),

    CTE4
    AS
    (
    SELECTT4.SYMBOL, CONVERT(DATE, T4.DATE_DATETIME) AS TRADE_DATE, SUM(T4.FIELD1 * T4.FIELD2) AS VALUE4
    FROMdbo.StockDB AS T4
    WHERET4.FIELD2 = T4.FIELD4 AND T4.TYPE = 'D'
    GROUP BYT4.SYMBOL, CONVERT(DATE, T4.DATE_DATETIME)
    )

    INSERT INTO DBO.StockData
    SELECTT1.SYMBOL,
    T1.TRADE_DATE,
    T1.VALUE1,
    T2.VALUE2,
    T3.VALUE3,
    T4.VALUE4
    FROMCTE1 AS T1
    JOINCTE2 AS T2 ON T1.SYMBOL = T2.SYMBOL AND T1.TRADE_DATE = T2.TRADE_DATE
    JOINCTE3 AS T3 ON T3.SYMBOL = T2.SYMBOL AND T3.TRADE_DATE = T2.TRADE_DATE
    JOINCTE4 AS T4 ON T4.SYMBOL = T3.SYMBOL AND T4.TRADE_DATE = T3.TRADE_DATE

    Thank you in advance!

  • for some reason the spacing for some of the lines are messed up.  the words are missing spaces between them.  hopefully this isn't an issue for anyone

  • It's difficult to help without seeing the actual execution plan and the DDL for StockDB (assuming that is a table rather than a database!)

    For a quick fix, try the divide and conquer approach. Push the results of each of the CTEs into temp tables and then use these in the final INSERT.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • and the query supplied can likely be replaced with a single one

    insert into DBO.StockData
    select t.SYMBOL
    , t.TRADE_DATE
    , t.VALUE1
    , t.VALUE2
    , t.VALUE3
    , t.VALUE4
    from (
    select T4.SYMBOL
    , convert(date, T4.DATE_DATETIME) as TRADE_DATE
    , sum(case when T4.FIELD2 = T4.FIELD3 and T4.TYPE = 'A' then T4.FIELD1 * T4.FIELD2 else 0 end) as VALUE1
    , sum(case when T4.FIELD2 = T4.FIELD4 and T4.TYPE = 'B' then T4.FIELD1 * T4.FIELD2 else 0 end) as VALUE2
    , sum(case when T4.FIELD2 = T4.FIELD3 and T4.TYPE = 'C' then T4.FIELD1 * T4.FIELD2 else 0 end) as VALUE3
    , sum(case when T4.FIELD2 = T4.FIELD4 and T4.TYPE = 'D' then T4.FIELD1 * T4.FIELD2 else 0 end) as VALUE4
    , max(case when T4.FIELD2 = T4.FIELD3 and T4.TYPE = 'A' then 1 else 0 end) as TypeA
    , max(case when T4.FIELD2 = T4.FIELD4 and T4.TYPE = 'B' then 1 else 0 end) as TypeB
    , max(case when T4.FIELD2 = T4.FIELD3 and T4.TYPE = 'C' then 1 else 0 end) as TypeC
    , max(case when T4.FIELD2 = T4.FIELD4 and T4.TYPE = 'D' then 1 else 0 end) as TypeD

    from dbo.StockDB as T4
    where (T4.FIELD2 = T4.FIELD4 and T4.TYPE in ('B', 'D'))
    or (T4.FIELD2 = T4.FIELD3 and T4.TYPE in ('A', 'C'))
    group by T4.SYMBOL
    , convert(date, T4.DATE_DATETIME)

    ) t
    where t.TypeA = 1
    and t.TypeB = 1
    and t.TypeC = 1
    and t.TypeD = 1
  • Temp tables should work, but for best performance be sure to create a unique clustered index on the temp tables to aid in the subsequent joins.  You'll want to create the index before loading the table.

    Specifically:

    DROP TABLE IF EXISTS #temp1;
    SELECT TOP (0) T1.SYMBOL, CONVERT(DATE, T1.DATE_DATETIME) AS TRADE_DATE, SUM(T1.FIELD1 * T1.FIELD2) AS VALUE1
    INTO #temp1
    FROM dbo.StockDB AS T1
    WHERE 0 = 1;

    ALTER TABLE #temp1 ADD UNIQUE CLUSTERED ( SYMBOL, TRADE_DATE ) WITH ( FILLFACTOR = 100 );

    INSERT INTO #temp1
    SELECT TT1.SYMBOL, CONVERT(DATE, T1.DATE_DATETIME) AS TRADE_DATE, SUM(T1.FIELD1 * T1.FIELD2) AS VALUE1
    FROM dbo.StockDB AS T1
    WHERE T1.FIELD2 = T1.FIELD3 AND T1.TYPE = 'A'
    GROUP BYT1.SYMBOL, CONVERT(DATE, T1.DATE_DATETIME)

    And likewise for the other 3 temp tables.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • Thank you both.  The query works now.

Viewing 6 posts - 1 through 5 (of 5 total)

You must be logged in to reply to this topic. Login to reply