【问题标题】:SQL Server Performance of Query with and without using CTE使用和不使用 CTE 的 SQL Server 查询性能
【发布时间】:2017-05-29 19:54:39
【问题描述】:

我有两个不同的查询,每页返回 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;

【问题讨论】:

  • 你的测试揭示了什么?
  • 我没有比较它们
  • 不要认为 CTE 会改变查询计划,但要提出一个替代方案:您也可以在第一个查询中使用 Count 和窗口函数(假设您有 sql server 2008或更新)。例如将字段count(1) over () cnt 添加到第一个查询将添加一个名为 cnt 的字段,其中包含查询返回的所有记录的计数
  • 是的,你是对的,但我认为 CTE 将是不错的选择,因为使用 CTE 我只能在单独的记录集中选择一次计数,而不是对每一行重复。

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


【解决方案1】:

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

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;

至于性能,这取决于您是测量到 first 行还是 last 行的时间。您的初始查询可以在生成结果时开始返回结果,因为没有 ORDER BYGROUP BY 或窗口函数。这与 CTE 的存在无关。

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

您应该测试一下查询是否满足您的性能需求。

【讨论】:

  • 使用窗口函数效率高吗?
  • @alsha 。 . .窗口函数应该是最有效的方法。
【解决方案2】:

CTE-s 和视图都是优化边界。 IE。查询计划将无法与外部查询一起优化WITH 查询。在您的情况下,这不是什么大问题,因为外部查询很简单。这是两个表的Cartesian Product

通常不鼓励使用笛卡尔积。但是,views 之一只包含一行。所以应该没问题。

【讨论】:

  • 所以这两个查询之间的差异并不大。正确的?因为对我来说,计数不如性能重要。 :)
  • 其实关心的是第一次查询只选择了10条记录。但在第二个查询中,外部查询中没有 CTE 中的分页限制。那么,我很好奇选择内存中的所有记录会产生更大的影响吗?
  • Awm OFFSET 子句...在这种情况下它影响。 CTE 版本将首先检索不必要的行,然后过滤不需要的行。
  • 第一件事:您需要根据窗口还是根据完整的TempResult 查询来计算TempCount .MaxRows?每种方法都需要不同的查询。您也可以检查表变量或临时表。
  • 无论是从窗口还是从 TempResult 查询,但资源效率更高
【解决方案3】:

由于你要进行分页和查找总记录,所以我使用窗口功能。

它通过单​​行号功能为我提供了帮助。

请更正查询的其余部分。如Calculate @From 和@To 。正确的row_number () 部分适合您的需要。还要注意commneted 部分并使用更快的部分。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    相关资源
    最近更新 更多