使用连接或变量查询时查看使用整个表

时间:2018-04-10 23:54:01

标签: sql tsql view sql-server-2014 common-table-expression

我有一个通过递归构建部门结构的视图。

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

1 个答案:

答案 0 :(得分:0)

我建议将查询计划与以下查询进行比较。

SELECT * FROM sys.dm_exec_plan_attributes (plan_handle)

希望您的问题能够通过使用来解决 的 SET ARITHABORT ON

`。