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

视图中的SQL CTE与存储过程中的临时表,sql,sql-server,performance,common-table-expression,temp-tables,Sql,Sql Server,Performance,Common Table Expression,Temp Tables,请容忍我,我知道这很复杂 我有一张包含公寓的桌子,还有一张包含这些公寓的租约。我的任务是从列表中选择最相关的租约。一般来说,这意味着最新的租赁,但有一些怪癖使得它比按日期订购更复杂 这让我在视图中创建了这个公共表表达式查询,然后在存储过程中与其他一些查询连接,以获得所需的结果: WITH TempTable AS ( SELECT l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID, ROW_NUM

请容忍我,我知道这很复杂

我有一张包含公寓的桌子,还有一张包含这些公寓的租约。我的任务是从列表中选择最相关的租约。一般来说,这意味着最新的租赁,但有一些怪癖使得它比按日期订购更复杂

这让我在视图中创建了这个公共表表达式查询,然后在存储过程中与其他一些查询连接,以获得所需的结果:

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子句更好地限制Temp表中的查询。由于表中有16栋建筑的10000多个租约,使用WHERE进行筛选的能力可能会使受影响的行减少90%-95%

考虑到这一切,我在这里遗漏了什么引人注目的东西吗?我是否在视图中做了一些错误的事情,可能会导致糟糕的性能,或者只是临时表中较小的结果集击败CTE中不受限制的结果集的问题

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


编辑2:我可以使用基于表的函数而不是视图吗?这是否允许我预先限制受影响的行,并且仍然在与其他表的联接中使用结果数据集?如果它能工作,并且性能良好,这将允许我将业务逻辑保留在函数的一个位置,而不是将其复制到几十个存储过程中。

为了解决这个问题,我最后做了以下几点:

我没有使用视图连接2或3个表中所有可能的行,而是创建了一个基于表的函数来进行相同的基本查询。作为我传入Building 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)
结果是,它大大减少了所需的联接数量,并大大加快了查询速度


然后,我将所有依赖视图的存储过程改为使用该函数,这将大大提高性能。

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

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
这样做将允许将使用视图的位置的边界应用于子查询,而CTE案例没有边界


与表值函数相比,视图在并行执行计划方面的问题更少,尽管这一个可能会被内联,使它们实际上完全相同

请选择哪个版本的SQL Server?行数在2008+1时更好。您如何通过建筑id或非建筑id从具有过滤器的视图中选择数据?2.请发布表结构和索引3。请发布坏查询和好查询的执行计划不幸的是,这是SQL Server 2005。由托管公司管理,因此我无法控制升级。数据是通过BuildingID@oryol上的过滤器从视图中选择的。执行计划的图形版本非常庞大。有更好的方式显示它们吗?执行set showplan_text on,然后执行查询。另外,请添加到创建DB结构表和索引的post脚本中