我在使用层次结构数据类型时遇到了速度问题,当我在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吗?