繁体   English   中英

存储过程中的视图vs临时表中的SQL CTE

[英]SQL CTE in a View vs Temp Table in a Stored Procedure

请多多包涵-我知道这很复杂。

我有一个包含公寓的表,另一个包含这些公寓的租约。 我的任务是从列表中选择“最相关”的租约。 通常,这意味着最新的租约,但是有些怪癖使它变得比仅按日期订购更为复杂。

这导致我在View内创建此公用表表达式查询,然后与存储过程内的其他多个JOIN联接以获得所需的结果:

WITH TempTable AS (
    SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
                ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
    FROM    dbo.NPleaseapplicant AS l INNER JOIN
            dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code

)

SELECT  BuildingID, ApartmentID, LeaseID, ApplicantID
FROM    TempTable
WHERE   RowNumber = 1

这可以工作并返回正确的结果。 我面临的挑战是非常慢的性能。

作为测试,我在存储过程中创建了一个临时表而不是使用View,并获得了更好的性能:

CREATE TABLE #Relevant (
    BuildingID int,
    ApartmentID int,
    LeaseID int,
    ApplicantID int,
    RowNumber int
)

INSERT INTO #Relevant (BuildingID, ApartmentID, LeaseID, ApplicantID, RowNumber)
SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
            ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
FROM    dbo.NPleaseapplicant AS l INNER JOIN
        dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code
WHERE   (l.BuildingID = @BuildingID)

DROP TABLE #Relevant

乍一看,这并没有加给我。 我听说临时表的性能非常差。 麻烦的是,我可以使用在视图中无法使用的WHERE子句更好地限制临时表中的查询。 由于表格中16座建筑物的租约超过10,000个,因此使用WHERE进行过滤的功能可能会使受影响的行减少90%-95%。

牢记所有这些,在这里我缺少什么明显的东西吗? 我在View上做错了什么,可能会导致糟糕的性能,还是只是Temp表中较小的结果集超过了CTE中不受限制的结果集的问题?

编辑:我应该补充一点,选择“最相关的租约”的这种业务逻辑是系统中许多报告的关键。 这就是为什么将其放置在View内的原因。 该视图为我们提供了“一次写入,多次使用”的功能,而存储过程中的临时表则需要为系统中的每个其他存储过程重新创建。 丑陋。

编辑#2:我可以使用基于表的函数代替视图吗? 这将允许我限制受影响的行,并且仍然将JOINT中的结果数据集与其他表一起使用吗? 如果它可以正常工作-并且具有良好的性能-这将使我可以将业务逻辑放在一个位置(该功能),而不必在数十个存储过程中复制它。

只是为了鞠躬,这就是我最终要做的事情:

我没有使用视图来联接2个或3个表中的所有可能的行,而是创建了一个基于表的函数,该函数进行相同的基本查询。 作为参数之一,我传入建筑物ID,并在WHERE子句中使用它,如下所示:

SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
            ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
FROM    dbo.NPleaseapplicant AS l INNER JOIN
        dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code
WHERE  (l.BuildingID = @BuildingID)

结果是它大大减少了所需的联接数,并极大地加快了查询速度。

然后,我将所有依赖于View的存储过程更改为使用Function,然后更改bingo -极大地提高了性能。

您还可以使用子查询语法重新编写视图:

SELECT  BuildingID, ApartmentID, LeaseID, ApplicantID
FROM
(
SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
                ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
    FROM    dbo.NPleaseapplicant AS l INNER JOIN
            dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code

)subquery
WHERE   RowNumber = 1

这样做将允许将where(正在使用视图的位置)边界应用于子查询,而对CTE大小写则没有边界。

与表值函数相比,视图在并行执行计划方面的问题更少(尽管无论如何都可以内联该视图,从而使它们实际上相同)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM