【问题标题】:SQL select field causing major performance problemSQL 选择字段导致主要性能问题
【发布时间】:2011-06-23 20:19:41
【问题描述】:

我有一个存储过程,可以加入许多表并从中选择字段。其中一张表是临时表。

SELECT
    a.Field1,
    a.Field2,
    b.Field3,
    b.Field4,
    c.Field5
FROM table1 a
    LEFT JOIN #table2 b ON a.Field1 = b.Field1
    INNER JOIN table3 c ON a.Field1 = c.Field1

以上操作需要 10 多分钟,但是如果我从选择中注释掉两个 b 字段,同时保留连接,它只需几秒钟即可运行。

我已将其从程序中删除以简化和相同的行为。执行计划也几乎相同。

感谢任何帮助。

【问题讨论】:

  • 这两个字段的数据类型是什么?
  • char(1)。它们是“Y”或“N”。
  • 嗯,这让我的理论认为它们是宽领域,因此需要更长的时间来传递数据。但它确实解释了为什么索引可能没有帮助,没有足够的特异性。
  • 你看的是实际的执行计划还是只是估计的?
  • 实际上,对不相关的表进行了几次索引扫描,当这些字段被注释掉时也会出现。

标签: sql performance sql-server-2005 sql-execution-plan


【解决方案1】:

临时表有多少行,临时表中的“Field2”是主键吗?

如果您没有从左连接的右表中选择任何行,并且连接是主键(或可能是唯一键),并且您没有引用右表中的列,SQL Server 可以避免必须访问临时表(因为存在或不存在连接行对最终结果没有影响):

示例。表设置:

create table T1 (
    ID int not null primary key,
    Col1 varchar(10) not null
)
go
insert into T1 (ID,Col1)
select 1,'a' union all
select 2,'b' union all
select 3,'c'
go
create table #t2 (
    ID int not null primary key,
    Col2 varchar(10) not null
)
go
insert into #t2 (ID,Col2)
select 1,'d' union all
select 2,'e' union all
select 4,'f'
go
create table #t3 (
    ID int not null,
    Col3 varchar(10) not null
)
go
insert into #t3 (ID,Col3)
select 1,'d' union all
select 2,'e' union all
select 1,'f'

以及查询:

select T1.ID,T1.Col1 from T1 left join #t2 t2 on T1.ID = t2.ID
select T1.ID,T1.Col1,t2.Col2 from T1 left join #t2 t2 on T1.ID = t2.ID
select T1.ID,T1.Col1 from T1 left join #t3 t3 on T1.ID = t3.ID
select T1.ID,T1.Col1,t3.Col2 from T1 left join #t2 t3 on T1.ID = t3.ID

在除第一个查询之外的所有查询中,连接都按预期进行。但是因为#t2中行的存在与否不会影响第一个查询的最终结果,所以它完全避免了执行连接。

但如果不是这样(而且我希望它在查询计划中会有明显的不同)

【讨论】:

  • 这是主键!太感谢了。我将 PK 添加到临时表中,并且索引速度非常快。
  • @Dustin - 好吧,这很尴尬 - 提到 PK 几乎是我的回答中附带的,但我很高兴它帮助激发了一些东西。
【解决方案2】:

您是否尝试过反转联接? (尽管您在示例查询中缺少表 c 的连接条件)

SELECT
    a.Field1,
    a.Field2,
    b.Field3,
    b.Field4,
    c.Field5
FROM table1 a
    INNER JOIN table3 c
    LEFT JOIN #table2 b ON a.Field1 = b.Field1

【讨论】:

  • 对不起,错字,因为这只是一个示例。 JOIN 顺序无关紧要,大约还有 10 个其他连接。我已将范围缩小到选择范围。
【解决方案3】:

我会尝试将包含列的索引添加到#table2,看看是否有帮助:

CREATE NONCLUSTERED INDEX IX_table2
    ON #table2 (Field1)
    INCLUDE (Field3, Field4);

【讨论】:

    【解决方案4】:

    如何分两部分运行查询。使第一部分尽可能严格,然后只在过滤后的集合上进行外连接。

    SELECT    a.Field1,   
              a.Field2,    
              b.Field3,       
              c.Field5
    INTO #t
    FROM table1 a   
        INNER JOIN table3 c ON a.Field1 = c.Field1
    
    SELECT t.Field1,
           t.field2,
           b.field3,
           b.field4,
           t.field5
    FROM #t t
         LEFT OUTER JOIN #table2 b ON t.Field1 = b.Field1            
    

    【讨论】:

      【解决方案5】:
      select * into #temp from table1
      select * into #temp1 from table2
      select * into #temp2 from table3
      
      
      SELECT
          a.Field1,
          a.Field2,
          b.Field3,
          b.Field4,
          c.Field5
      FROM #temp a
          LEFT JOIN #temp1 b ON a.Field1 = b.Field1
          INNER JOIN #temp2 c ON a.Field1 = c.Field1
      
      
      
      if(Object_Id('TempDB..#temp') Is Not Null)
      Begin
          Drop table #temp
      End
      if(Object_Id('TempDB..#temp1') Is Not Null)
      Begin
          Drop table #temp1
      End
      if(Object_Id('TempDB..#temp2') Is Not Null)
      Begin
          Drop table #temp2
      End
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-10
        • 2013-01-07
        • 1970-01-01
        • 1970-01-01
        • 2019-05-04
        • 2013-11-08
        • 2013-04-01
        • 2017-12-10
        相关资源
        最近更新 更多