SQL Server查询性能 - 删除哈希匹配(内部联接)的需要

Tim*_*eel 20 sql performance sql-server-2008

我有以下查询,它做的很少,并且是我在整个系统中进行的连接类型的示例.

select t1.PrimaryKeyId, t1.AdditionalColumnId
from TableOne t1
    join TableTwo t2 on t1.ForeignKeyId = t2.PrimaryKeyId
    join TableThree t3 on t1.PrimaryKeyId = t3.ForeignKeyId
    join TableFour t4 on t3.ForeignKeyId = t4.PrimaryKeyId
    join TableFive t5 on t4.ForeignKeyId = t5.PrimaryKeyId
where 
    t1.StatusId = 1
    and t5.TypeId = 68
Run Code Online (Sandbox Code Playgroud)

所有连接列都有索引,但性能不是很好.检查查询计划时会发现很多哈希匹配(内部联接),当我真的想要看到嵌套循环连接时.

每个表中的记录数如下:

select count(*) from TableOne
Run Code Online (Sandbox Code Playgroud)

= 64393

select count(*) from TableTwo
Run Code Online (Sandbox Code Playgroud)

= 87245

select count(*) from TableThree
Run Code Online (Sandbox Code Playgroud)

= 97141

select count(*) from TableFour
Run Code Online (Sandbox Code Playgroud)

= 116480

select count(*) from TableFive
Run Code Online (Sandbox Code Playgroud)

= 62

提高此类查询性能的最佳方法是什么?

gbn*_*gbn 29

初步想法:

  1. 更改为EXISTS(将等连接更改为半连接)
  2. 您需要在t1.StatusId,t5.TypeId和INCLUDE t1.AdditionalColumnID上有索引.

我不担心你的加入方法......

就个人而言,我从未使用过JOIN提示.它们仅适用于您在该时间点拥有的数据,索引和统计信息.随着这些更改,您的JOIN提示会限制优化器

select t1.PrimaryKeyId, t1.AdditionalColumnId
from
    TableOne t1
where 
    t1.Status = 1
    AND EXISTS (SELECT *
        FROM
          TableThree t3
          join TableFour t4 on t3.ForeignKeyId = t4.PrimaryKeyId
          join TableFive t5 on t4.ForeignKeyId = t5.PrimaryKeyId
        WHERE
          t1.PrimaryKeyId = t3.ForeignKeyId
          AND
          t5.TypeId = 68)
    AND EXISTS (SELECT *
        FROM
          TableTwo t2
        WHERE
          t1.ForeignKeyId = t2.PrimaryKeyId)
Run Code Online (Sandbox Code Playgroud)

tableOne的索引..其中之一

  • (Status, ForeignKeyId) INCLUDE (AdditionalColumnId)
  • (ForeignKeyId, Status) INCLUDE (AdditionalColumnId)

tableFive的索引...可能 (typeID, PrimaryKeyId)

编辑:更新了JOINS和EXISTS以匹配问题修复


And*_*mar 11

SQL Server非常擅长优化查询,但它也很保守:它可以优化最坏情况下的查询.循环连接通常会导致索引查找和每行的书签查找.由于循环连接会导致大型集合的显着降级,因此SQL Server对使用它们犹豫不决,除非它确定行数.

您可以使用forceseek 查询提示强制索引查找:

inner join TableTwo t2 with (FORCESEEK) on t1.ForeignKeyId = t2.PrimaryKeyId
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用loop关键字强制循环连接:

inner LOOP join TableTwo t2 on t1.ForeignKeyId = t2.PrimaryKeyId
Run Code Online (Sandbox Code Playgroud)

查询提示限制了SQL Server的自由,因此它无法再适应变化的环境.最佳做法是避免查询提示,除非有没有它们无法满足的业务需求.