我有一个通过递归构建部门结构的视图。
Department:
Cust(fk) Department_Id(pk) Name
1 1 DeptA
1 2 DeptB
1 3 DeptC
1 4 DeptC2
1 5 DeptQ
Department Map:
Department_Id ParentId
1 null
2 1
3 2
4 2
5 1
请原谅桌面结构。我知道这两个表可以合并,但它的旧设计很难改变。视图构建了层次结构,因此我们可以将它们组合在一起。
Department View Output (vwDepartmentStructure):
Cust BottomId DepartmentId DepartmentName Position
1 1 1 DeptA 1
1 2 2 DeptB 1
1 2 1 DeptA 2
1 3 3 DeptC 1
1 3 2 DeptB 2
1 3 1 DeptA 3
1 4 4 DeptC2 1
1 4 2 DeptB 2
1 4 1 DeptA 3
1 5 5 DeptQ 1
1 5 1 DeptA 2
由于我们在系统中拥有大量数据,因此视图本身恢复得非常快。当我尝试使用BottomId(索引字段)和非硬编码值查询此视图时,会出现问题。
返回非常快(不到一秒):
select * from vwDepartmentStructure s where s.BottomId = 4
然而,这是一个不同的故事:
Declare @bottomId int = 4
select * from vwDepartmentStructure s where s.BottomId = @bottomId
根据我们系统中的数据运行大约15-20秒。我查看了执行计划,它说它抓住了所有可能的变化(整个视图结果)并在最后过滤它;然而,硬编码值仅检索BottomId。当我尝试将视图与其他表连接时(这是我发现问题的地方),这也很慢。
select * from person p
inner join vwDepartmentStructure s on s.Cust = p.CustomerId and s.BottomId = s.Department
where p.Id = 123
由于构建了执行计划,我确实阅读了有关硬编码值如何更好地执行的内容,但变量会改变执行计划,使其更加动态但速度更慢。然而,抛出循环的是这个查询与硬编码的查询运行速度相同:
Declare @customer int = 1
select * from vwDepartmentStructure s where s.Cust = @customer and s.BottomId = 4
在抓取整个表之前,我能做些什么来让它识别BottomId的变量值?
UPDATE 这是CTE:
USE [TESTDB]
GO
DROP VIEW [dbo].[vwTestRouting]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE VIEW [dbo].[vwTestRouting]
AS
WITH allDept (Cust, BottomDeptId, Position, DeptId, Manager_Key, MaxApproval, ParentId)
AS(
SELECT d.CustomerKey, d.DeptId, 1, d.DeptId, d.ManagerKey, d.MaxApproval, dm.ParentId
from Department d
inner join DepartmentMap dm on d.DeptId = dm.DeptId
UNION ALL
SELECT ad.Cust, ad.BottomDeptId, ad.Position + 1, d.DeptId, d.ManagerKey, d.MaxApproval, dm.ParentId
from allDept ad
inner join Department d on d.DeptId = ad.ParentId
inner join DepartmentMap dm on d.DeptId = dm.DeptId
)
select * from allDept;
GO
答案 0 :(得分:0)
我建议将查询计划与以下查询进行比较。
SELECT * FROM sys.dm_exec_plan_attributes (plan_handle)
希望您的问题能够通过使用来解决
的 SET ARITHABORT ON
强>
`。