使用和不使用CTE的SQL Server查询性能

时间:2017-05-29 09:24:18

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

我有两个不同的查询,每页返回10条记录。但是在我的第二个查询中,我已经更新了它以返回总记录数,并且已经使用CTE实现了。现在我不愿意使用它,并想知道性能影响,因为现在它在Query 02中使用了CTE。 CTE会选择内存中表的所有记录并使其占用大量内存吗?这两个查询之间的性能差异有多大?因为如果存在巨大的性能差异,那么我可以跳过总计数。请建议。

DECLARE
@PageSize tinyint=10,
@PageOffset int=0;

--Query 01
SELECT
    App.Id,
    Users.FirstName+' '+Users.LastName as Name,
    App.Date
FROM
    App
    INNER JOIN Users ON App.UserId = Users.Id
WHERE
    App.FolderId = 1
ORDER BY
    App.Date DESC
OFFSET @PageOffset ROWS FETCH NEXT @PageSize ROWS ONLY;

--Query 02
WITH TempResult AS(
    SELECT
        App.Id,
        Users.FirstName+' '+Users.LastName as Name,
        App.Date
    FROM
        App
        INNER JOIN Users ON App.UserId = Users.Id
    WHERE
        App.FolderId = 1
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)
SELECT *
FROM TempResult, TempCount
ORDER BY
    TempResult.Date DESC
OFFSET @PageOffset ROWS FETCH NEXT @PageSize ROWS ONLY;

3 个答案:

答案 0 :(得分:0)

CTE-s以及视图都是优化边界。即查询计划无法与外部查询一起优化WITH查询。在你的情况下,它不是一个问题,因为外部查询很简单。它是两个表中的Cartesian Product个。

通常不鼓励笛卡尔积。但是,其中一个视图只包含一行。所以应该没问题。

答案 1 :(得分:0)

我不明白你为什么要使用多个子查询。编写查询的最佳方法是使用窗口函数:

for tmpfile in /home/asmita/tmp
    do
    mv "$tmpfile" "C_${tmpfile}"
    mv "C_${tmpfile}" /home/tgasmita
done

至于性能,这取决于您是否正在测量第一行行或最后一行行的时间。您的初始查询可以在生成结果时开始返回结果,因为没有SELECT a.Id, (u.FirstName + ' '+ u.LastName) as Name, a.Date, COUNT(*) OVER () as MaxRows FROM App a INNER JOIN Users u ON a.UserId = u.Id WHERE a.FolderId = 1; ORDER BY或窗口函数。这与CTE的存在无关。

任何具有总计数的版本都需要生成整个结果集。这需要在返回任何内容之前在内部生成所有结果。

您应该测试以查看查询是否符合您的性能需求。

答案 2 :(得分:0)

由于你要进行分页并找到两个总记录,我使用窗口函数。

它使用单行号功能帮助我。

请更正查询的其余部分。喜欢计算@From和@To。纠正row_number()部分,以满足您的需要。还要注意通知部分并使用更快的部分。

DECLARE @PageSize tinyint=10,
@PageOffset int=0;

--Query 01
;with CTE as
(
SELECT
    App.Id,
    Users.FirstName+' '+Users.LastName as Name,
    App.Date ,ROW_NUMBER()over(order by date desc) rn
FROM
    App
    INNER JOIN Users ON App.UserId = Users.Id
WHERE
    App.FolderId = 1

)
select * 
,(select max(rn) from cte) TotalRecords
--,(select top 1 rn from cte order by rn desc) TotalRecords
from cte
where rn between @From and @To