0
我們通常會被要求在報表中包含特定級別的層次結構,並且我正在尋找一種方法來加快查詢性能並使用hierarchyid。我做了一些測試,並且我有問題,但我認爲性能會更好。以下是針對給定條目抽取2到4級的示例。我想通過GetAncestor()函數結合hierarchyid的級別來實現這一點。第一個查詢看起來很快,但它被硬編碼爲只返回某一級別的行,以避免使用負值炸燬GetAncestor查詢。第二個樣本解決了這個問題,但速度要慢得多。理想的第二種選擇是我想使用但它不夠快。SQL hierarchyId上的GetAncestor查詢總是會拉動某些級別
--drop table #hier
CREATE TABLE #hier
(
rec_ID int NOT NULL,
rec_NAME varchar(6),
nodeID hierarchyid NULL,
lvl AS [nodeid].[GetLevel]() PERSISTED
) ON [PRIMARY]
GO
ALTER TABLE #hier ADD CONSTRAINT
rec_ID PRIMARY KEY CLUSTERED
(
rec_ID
) WITH(STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX IX_hier_nodeID ON #hier
(
nodeID
) WITH(STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE #hier SET (LOCK_ESCALATION = TABLE)
GO
insert into #hier (rec_ID, rec_NAME, nodeID)
SELECT 1, 'CEO', cast('/' as hierarchyid)
union
SELECT 2, 'VP1', cast('/1/' as hierarchyid)
union
SELECT 3, 'VP2', cast('/2/' as hierarchyid)
union
SELECT 4, 'VP3', cast('/3/' as hierarchyid)
union
SELECT 5, 'Mgr1', cast('/1/1/' as hierarchyid)
union
SELECT 6, 'Mgr2', cast('/1/2/' as hierarchyid)
union
SELECT 7, 'Super1', cast('/1/2/1/' as hierarchyid)
union
SELECT 8, 'Ldr1', cast('/1/2/1/1/' as hierarchyid)
union
SELECT 9, 'Work1', cast('/1/2/1/1/1/' as hierarchyid)
union
SELECT 10, 'Work2', cast('/1/2/1/1/2/' as hierarchyid)
union
SELECT 11, 'Work3', cast('/1/2/1/1/3/' as hierarchyid)
GO
-- this runs fast but is hard coded to a level
declare @recname varchar(6)
set @recname = 'Work3'
select
x.rec_name
,x.lvl
,(select rec_name from #hier where nodeid = x.nodeid.GetAncestor(x.lvl - 2)) as l2
,(select rec_name from #hier where nodeid = x.nodeid.GetAncestor(x.lvl - 3)) as l3
,(select rec_name from #hier where nodeid = x.nodeid.GetAncestor(x.lvl - 4)) as l4
from #hier x
where x.rec_name = @recname
and x.lvl >= 4
-- this works for all levels but runs too slow
set @recname = 'Mgr2'
select
x.rec_name
,x.lvl
,case
when x.lvl >=2 then (select rec_name from #hier where nodeid = x.nodeid.GetAncestor(x.lvl - 2))
else '*N/A' end as l2
,case
when x.lvl >=3 then (select rec_name from #hier where nodeid = x.nodeid.GetAncestor(x.lvl - 3))
else '*N/A' end as l2
,case
when x.lvl >=4 then (select rec_name from #hier where nodeid = x.nodeid.GetAncestor(x.lvl - 4))
else '*N/A' end as l2
from #hier x
where x.rec_name = @recname
這是一個很好的觀點,我應該首先深入研究指標。我也應該創建一個帶有循環和更多行的示例以更好地測試性能。最初,我想也許有一種方法來重新查詢查詢,但也許這只是一個簡單的索引問題。在這個例子中,rec_ID是唯一的,nodeID應該是唯一的(假設我的維護工作正常)。讓我研究一下你使用INCLUDE選項 - 我不熟悉這一點。 – pretzelb 2014-10-08 13:42:52