快速从VIEW中选择,但WHERE会导致速度变慢

时间:2016-04-05 03:42:05

标签: sql sql-server sql-server-2014

我有一个非常复杂的视图,它使用层次结构表结构,它使用层次结构数据类型,并返回丢失的位置。位置是层次结构表。

视图在CTE中执行一个数据透视,然后将其与一些额外的连接一起使用,以便为开发人员生成有用的数据列表。

以下是观点:

CREATE VIEW [dbo].[vwLocations] WITH SCHEMABINDING
AS
    WITH p AS 
    (
    SELECT ID,
            [1] AS Facility,
            [2] AS Community,
            [3] AS Unit,
            [4] AS Pod,
            [5] AS Cell,
            [6] AS Bed,
            [7] AS Zone,
            [8] AS Building,
            [9] AS Room 
        FROM (
            SELECT 
                p.ID, 
                l.[Name], 
                l.[Level] + CASE WHEN l.LocationTypeID IN(11,12,13) THEN 5 ELSE 0 END AS Level -- Note, 11,12 and 13 are Non-Accomodation types, so the level needs to move to the Non-Accomodation area
            FROM dbo.Location AS l
            INNER JOIN dbo.Location AS p
                ON p.[Path].IsDescendantOf(l.[Path]) = 1
        ) AS p
        PIVOT (
            MAX(Name)
            FOR [Level] IN (
                [1],
                [2],
                [3],
                [4],
                [5],
                [6],
                [7],
                [8],
                [9]
            )
        ) AS pvt
    )
    SELECT ISNULL(l.ID,-999) AS LocationID, -- Done to allow EF to use the view. A view needs something that looks like a KEY.
            l.ParentID AS ParentID,
            LocationTypeID,
            lt.Description AS LocationType,
            l.GeoLocation,
            l.Name,
            p.Facility,
            p.Community,
            p.Unit,
            p.Pod,
            p.Cell,
            p.Bed,
            p.Zone,
            p.Building,
            p.Room

        FROM dbo.Location l
        INNER JOIN p
            ON p.ID = l.id
        INNER JOIN ref.LocationType lt
            ON lt.ID = l.LocationTypeID
GO 

SELECT * FROM vwLocations在大约60ms内运行。我很高兴。当我将视图连接到某些表以生成结果集时,此查询也很快:

SELECT 
    Per.Firstname, 
    per.Surname, 
    v.* 
FROM person per
INNER JOIN dbo.Prisoner pri
    ON pri.PersonID = per.ID
LEFT JOIN dbo.vwLocations v
    ON v.LocationID = pri.CurrentAccommodationLocationID

运行时间不到半秒,返回800行。

然而,当我在查询中添加一个非常基本的WHERE子句时 - 时间会爆发4到6秒。

    SELECT 
        Per.Firstname, 
        per.Surname, 
        v.* 
    FROM person per
    INNER JOIN dbo.Prisoner pri
        ON pri.PersonID = per.ID
    LEFT JOIN dbo.vwLocations v
        ON v.LocationID = pri.CurrentAccommodationLocationID
    WHERE per.IsActive = 1

我很困惑为什么WHERE语句在与VIEW不同的表上会导致如此大幅度的速度损失。

以下是没有WHERE的查询的查询执行计划。 enter image description here

这是带有WHERE子句的查询的执行计划。 enter image description here

我错过了一个索引吗?不是,如果我通过它自己运行View,它很快。并返回所有行。所以我不确定这个观点是否有问题 - 尽管如此,这是唯一复杂的事情。

Execution plan WITH the where clause

Execution plan WITHOUT the where clause

编辑:

这是奇怪的事情。如果我在Person表中的另一列上进行过滤(此时,我在IsActive = 1上过滤),我会得到快速响应!所以,当我跑:

SELECT 
    Per.Firstname, 
    per.Surname, 
    v.*,
    *
FROM person per
INNER JOIN dbo.Prisoner pri
    ON pri.PersonID = per.ID
LEFT JOIN dbo.vwLocations v
    ON v.LocationID = pri.CurrentAccommodationLocationID
WHERE per.PersonTypeID = 7 

返回相同的行数(因为我知道所有活动人都是PersonType 7)。只有当我过滤IsActive(BIT NOT NULL)时,它才会变慢。

1 个答案:

答案 0 :(得分:0)

在查询中添加where子句导致了不同的计划并且不准确,因为统计数据在位置表上不准确。统计数据是获得良好计划的关键。

尝试更新查询中涉及的对象的统计信息,您将获得不同的计划..

enter image description here