Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimize temporal table with CTE

I create temporal table in order to set level :

CREATE TABLE [#DesignLvl]
(
    [DesignKey] INT,
    [DesignLevel] INT
);

WITH RCTE AS 
(
    SELECT
        *,
        1 AS [Lvl]
    FROM 
        [Design]
    WHERE 
        [ParentDesignKey] IS NULL

    UNION ALL

    SELECT
        [D].*,
        [Lvl] + 1 AS [Lvl]
    FROM 
        [dbo].[Design] AS [D]
    INNER JOIN 
        [RCTE] AS [rc] ON [rc].[DesignKey] = [D].[ParentDesignKey]
)
INSERT INTO [#DesignLvl]
    SELECT
        [DesignKey], [Lvl]
    FROM 
        [RCTE]

Once created, I used as LEFT JOIN in really big query as:

SELECT... 
FROM.. 
LEFT JOIN [#DesignLvl] AS [dl] ON d.DesignKey = dl.DesignKey
WHERE ...

The query works, but performance has fallen and the query now is too slow. Is there any way to optimize this table?

Execution plan of CTE

enter image description here

I try to add CLUSTERED index as:

CREATE TABLE [#DesignLvl]
(
    [DesignKey] INT,
    [DesignLevel] INT
);

CREATE CLUSTERED INDEX ix_DesignLvl 
    ON [#DesignLvl] ([DesignKey], [DesignLevel]);

Also try:

    CREATE TABLE [#DesignLvl] 
( [DesignKey] INT INDEX IX1 CLUSTERED ,
 [DesignLevel] INT INDEX IX2 NONCLUSTERED );

But I get same result, it took long to execute

like image 829
Jonathan Avatar asked Mar 04 '19 18:03

Jonathan


People also ask

Which is faster CTE or temp table?

Looking at SQL Profiler results from these queries (each were run 10 times and averages are below) we can see that the CTE just slightly outperforms both the temporary table and table variable queries when it comes to overall duration.

Can we use temp table in CTE?

Temp Tables are physically created in the tempdb database. These tables act as the normal table and also can have constraints, an index like normal tables. CTE is a named temporary result set which is used to manipulate the complex sub-queries data. This exists for the scope of a statement.

Is CTE faster than JOIN?

As you said that 'there is no difference between these two query in terms of performance', so I think in your simple example LEFT JOIN and CTE might have the same performance. I think the biggest benefit for using CTEs is readability.

Does CTE use tempdb?

Tempdb is a very special system database that is used to store temporary objects which are created by the users explicitly or by the internal system process. The following objects or operations use tempdb: Global and local temporary tables. Common table expressions (CTE)


2 Answers

The performance could be slower because a clustered index on the dbo.Design table is being accessed inside a nested loop. According to the cost estimate, the database is spending 66% of it's time scanning that index. Looping over that just makes it worse.

See related question

Consider changing the index on dbo.Design to be non-clustered, or try creating another temporary table with a non-clustered index and use that for your recursive query:

CREATE TABLE [#DesignTemp]
(
    ParentDesignKey INT,
    DesignKey INT
);

-- Insert the data, then create the index.
INSERT INTO [#DesignTemp]
SELECT
ParentDesignKey,
DesignKey
FROM [dbo].[Design];

COMMIT;

-- Try this index, or create indexes for individual columns if the plan works better at high volumes.
CREATE NONCLUSTERED INDEX ix_DesignTemp1 ON [#DesignTemp] (ParentDesignKey, DesignKey);

CREATE TABLE [#DesignLvl]
(
    [DesignKey] INT,
    [DesignLevel] INT
);

WITH RCTE AS 
(
    SELECT
        *,
        1 AS [Lvl]
    FROM 
        [DesignTemp]
    WHERE 
        [ParentDesignKey] IS NULL

    UNION ALL

    SELECT
        [D].*,
        [Lvl] + 1 AS [Lvl]
    FROM 
        [DesignTemp] AS [D]
    INNER JOIN 
        [RCTE] AS [rc] ON [rc].[DesignKey] = [D].[ParentDesignKey]
)
INSERT INTO [#DesignLvl]
    SELECT
        [DesignKey], [Lvl]
    FROM 
        [RCTE];
like image 191
bruceskyaus Avatar answered Sep 28 '22 08:09

bruceskyaus


Your question is incomplete, "query is slow", but which part of query is slow ?

CTEQuery or LEFT JOIN in really big query

I think Script of big query is required, along with details, like which table contain how many rows, their data type etc.

Throw more details about the big query.

Also let us know if any UDF is involve in join condition.

Why do you left join Temp table ? WHY NOT INNER JOIN

Test the performance separately or CTE and Big Query.

Once use [D].[ParentDesignKey] is not null in recursive part,

SELECT
        [D].*,
        [Lvl] + 1 AS [Lvl]
    FROM 
        [dbo].[Design] AS [D]
    INNER JOIN 
        [RCTE] AS [rc] ON [rc].[DesignKey] = [D].[ParentDesignKey]
and [D].[ParentDesignKey] is not null

NOTE : In CTE use only those columns which is require.

If it is possible to Pre- Calculate [Lvl],because Recursive CTE performance is specially bad involving lot of Records.

How many rows will be process in each CTE Query on average ?

If temp table will hold more than 100 rows then yes create Clustered index on it,

  CREATE CLUSTERED INDEX ix_DesignLvl 
        ON [#DesignLvl] ([DesignKey], [DesignLevel]);

If you are not using [DesignLevel] in join condition then remove from index.

Also ,Reveal index of table [dbo].[Design] and few data of DesignKey and ParentDesignKey.

There are several reason for getting Index Scan, one of them is Selectivity of Key .

So one DesignKey can have how many rows and one ParentDesignKey can have how many rows ?

So depending upon above answer Create Composite Clustered Index on both key of table [dbo].[Design]

So consider my answer is incomplete, I will update it accordingly.

like image 37
KumarHarsh Avatar answered Sep 28 '22 10:09

KumarHarsh