强制Sql server在合并连接中使用索引查找

Kaj*_*aja 2 sql-server optimization execution-plan sql-server-2012

我正在测试 sql server 中的合并加入。我有一个INNER JOIN并强制优化器执行以下操作MERGE JOIN

  • ID 在个人表中是主键
  • ID 在 Abteilung 表是主键
  • 这些表中没有其他索引

     select * from  [dbo].[Personal] as P inner join [dbo].[Abteilung] as A  
     on  P.[ID]= A.[Personal_ID]   OPTION (MERGE JOIN) 
    
    Run Code Online (Sandbox Code Playgroud)

然后优化器使用这个计划来运行我的查询:

在此处输入图片说明

我想强制优化器使用index seek而不是Table Scan

我为实现这个目标做了什么:

  • 在 Table Abteilung 中的列ID,上定义分组索引Personal_ID。如果我运行查询,执行计划是这样的变化:

在此处输入图片说明

这里我有聚集索引扫描,但没有聚集索引搜索

  • 使用FORCESEEK提示。如果我使用此提示,运行查询会发生错误:

由于此查询中定义的提示,查询处理器无法生成查询计划。在不指定任何提示且不使用 SET FORCEPLAN 的情况下重新提交查询。

  • 如果我在查询中添加 where 子句,则查询将更改为:

      select * from  [dbo].[Personal] as P inner join [dbo].[Abteilung] as A  
      on P.[ID]= A.[Personal_ID] where A.[Personal_ID]=2 
      OPTION (MERGE    JOIN)
    
    Run Code Online (Sandbox Code Playgroud)

    在此处输入图片说明 在这种情况下,我只有聚集索引扫描。

我的问题:

如何更改我的查询以在底线中包含聚集索引查找?

Aar*_*and 6

要获得聚集索引查找,您需要一个支持过滤器的聚集索引(例如,前导键必须是Personal_ID,而不是ID)。

如果没有前导列Personal_ID支持过滤器的索引,则不能强制查找。

这并不意味着您应该更改现有的聚集索引,除非这是您对表运行的唯一查询。

虽然您可以创建一个Personal_ID作为键列的非聚集索引,但是对该索引的查找可能不是您想要的 - 因为您正在使用SELECT * (您真的确定需要两个表中的所有列吗?),它无论如何都需要从聚集索引中获取其余的列,并且如果返回的行数超过一定数量,则在某些时候进行搜索(好吧,相当于伪装为搜索的范围扫描)+ 查找将比常规扫描更昂贵。

为什么你认为你需要在这里寻找?查询返回多少行,它们有多宽,需要多长时间?这只是教育性的,还是您假设搜索总是比扫描表现更好?(它不会,顺便说一句。)

一些有用的阅读: