自联接表vs cte递归

时间:2017-12-22 11:16:03

标签: sql sql-server tsql database-performance

我有好奇心。请在这里建议我最好的做法。

我有一个包含empname和mgr_name列的表测试,因为名称建议empname包含empname,mgr_name包含特定员工的经理名称。我的要求是找到那些至少向一位经理和管理人员报告的员工。

我写了一个查询,并返回正确的记录。

create table test(empname varchar(10),mgr_name varchar(10))

insert into test
values('a','b'),('b',null),('c',null),('d','f'),('f',null),('g',null),('h',null)

查询:

select a.empname
from test a , test b
where a.mgr_name =b.empname
union
select b.empname
from test a , test b
where a.mgr_name =b.empname

我尝试优化此查询并使用CTE而不是多次使用自连接中的表,如

;with cte as (
select *
from test

)
select a.empname
from cte a , cte b
where a.mgr_name =b.empname
union
select b.empname
from cte a , cte b
where a.mgr_name =b.empname

但我发现执行计划中没有任何改善。

在这种情况下,我需要您的帮助来决定优化查询,请在此情况下建议是否优化任何其他方法。

3 个答案:

答案 0 :(得分:0)

对指定指标(无)的优化会导致以下内容提供所有人员的列表,以及他们是(1)由某人管理还是(b)管理某人:

declare @Employees as Table ( EmployeeName VarChar(10), ManagerName  VarChar(10) );

insert into @Employees ( EmployeeName, ManagerName ) values
  ( 'a', 'b' ), ( 'b', null ), ( 'c', null ), ( 'd', 'f' ), ( 'f', null ), ( 'g', null ), ( 'h', null );

select distinct( Name ),
  case when exists
    ( select 42 from @Employees where EmployeeName = Name and ManagerName is not NULL ) then 1 else 0 end as IsManaged,
  case when exists
    ( select 42 from @Employees where ManagerName = Name ) then 1 else 0 end as IsManager
  from (
    select EmployeeName as Name
      from @Employees
    union all
    select ManagerName
      from @Employees
      where ManagerName is not NULL ) as PH;

-- Alternatively:
select Name, Max( IsManaged ) as IsManaged, Max( IsManager ) as IsManager
  from (
    select EmployeeName as Name, case when ManagerName is NULL then 0 else 1 end as IsManaged, 0 as IsManager
      from @Employees
    union all
    select ManagerName, 0, 1
      from @Employees
      where ManagerName is not NULL ) as PH
  group by Name;

支持自我管理。

答案 1 :(得分:0)

实际上,您的CTE没有做任何事情。您只是准确地复制一个表,因此与使用cte或test没有区别。你可能想做的事情如下:

; with cte as (
    select * -- This won't work because duplicate naming, but you can change that
    from test a, test b -- my soul weeps at this terrible syntax
)

无论如何,您不需要这样做。这是您想要的查询

select empname
from test
where mgr_name is not null
    or empname in (
        select mgr_name
            from test
    )

答案 2 :(得分:-1)

无需查询表格4次...只需检查mgr_name的值是否为 NULL

SELECT empname
FROM test
WHERE mgr_name IS NOT NULL
UNION
SELECT mgr_name
FROM test
WHERE mgr_name IS NOT NULL;

您仍然需要进行2次扫描,但除了隐式JOIN以及2次扫描之外(在查询中,表格在每次扫描时扫描两次) UNION)。