层次结构类型为

时间:2016-03-30 22:22:08

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

我在使用层次结构数据类型时遇到了速度问题,当我在StackOverflow上获得帮助时,我不知道如何解决它。

我有一个包含Locations的表,它是一个与父子相关的表。

CREATE TABLE [dbo].[Location](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ParentID] [int] NULL,
    [LocationTypeID] [int] NOT NULL,
    [GeoLocation] [geometry] NULL,
    [Name] [varchar](50) NOT NULL,
    [Description] [varchar](100) NOT NULL,
    [Path] [hierarchyid] NULL,
    [Level]  AS ([Path].[GetLevel]()) PERSISTED,
    [Deleted] [datetime] NULL,
    [CreatedDate] [datetime] NOT NULL,
    [CreatedUserID] [int] NOT NULL,
    [ModifiedDate] [datetime] NULL,
    [ModifiedUserID] [int] NULL,
    [Version] [timestamp] NOT NULL,
 CONSTRAINT [pk_location] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

然后我有一个视图,可以向开发人员返回更多有用的数据。

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 Location l
     CROSS APPLY dbo.fnPivotLocationHierarchy(l.ID) p
     INNER JOIN ref.LocationType lt
        ON lt.ID = l.LocationTypeID

这使用了以下功能。

CREATE FUNCTION [dbo].[fnPivotLocationHierarchy](@id int)
RETURNS TABLE
AS RETURN

    /*
        This function is used to pivot the Location table based on levels
        and paths to move to a wide view of the location data.
    */

    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
        WHERE p.ID = @id
    ) AS p
    PIVOT (
        MAX(Name)
        FOR [Level] IN (
            [1],
            [2],
            [3],
            [4],
            [5],
            [6],
            [7],
            [8],
            [9]
        )
    ) AS pvt;
GO

我希望索引可能有所帮助。我目前所拥有的只是主键,也是ParentID的索引。

CREATE NONCLUSTERED INDEX [ix_location_parentid] ON [dbo].[Location]
(
    [ParentID] ASC
)
INCLUDE (   [ID],
    [Description],
    [Name],
    [LocationTypeID],
    [Level],
    [Path]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

有没有办法可以改善这种表现?我试图将视图转换为索引视图,但是因为正在使用CROSS APPLY而无法使用。

编辑: 似乎可能不是这个问题的观点。我发现soemthing有点奇怪:

SELECT * FROM person per
INNER JOIN dbo.Prisoner pri
ON pri.PersonID = per.ID
INNER JOIN vwLocations v
ON v.LocationID = pri.CurrentAccommodationLocationID

执行计划: https://www.dropbox.com/s/rncglc1a05fnwfa/PlanWithoutWhereClause.sqlplan?dl=0

该查询在0.5秒内运行。它获取所有记录,没有任何过滤器。请注意,视图中有一行的囚犯只会出现(视图中的INNER连接),这是预期的。正如预期的那样,以770行回归。

但是,当我添加WHERE子句时,如下所示:

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

执行计划: https://www.dropbox.com/s/obo6fbmrp5o4yx4/PlanWithWhereClause.sqlplan?dl=0

相同行数(因为只有活动人员在视图中有行),但需要4.5秒。

存在NO WHERE子句时的查询计划: 帮助 - 不确定如何添加执行计划。我可以上传XML吗?

0 个答案:

没有答案