使用 in 语句在简单查询中进行哈希匹配内连接

Ado*_*rez 7 sql-server execution-plan tuning

我正在运行以下查询的执行计划:

select m_uid from EmpTaxAudit 
where clientid = 91682 
and  empuid = 42100176452603
and newvalue in('Deleted','DB-Deleted','Added')
Run Code Online (Sandbox Code Playgroud)

下面是执行计划:

执行计划

我在 ClientId 和 NewValue 列上的 EmpTaxAudit 表上有一个非聚集索引,上面显示为执行的 14.9%:

CREATE NONCLUSTERED INDEX [idx_EmpTaxAudit_clientid_newvalue] ON [dbo].

[EmpTaxAudit]
(
    [ClientID] ASC,
    [NewValue] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
Run Code Online (Sandbox Code Playgroud)

我还有一个非聚集唯一索引 PK,如下所示:

ALTER TABLE [dbo].[EmpTaxAudit] ADD  CONSTRAINT [PK_EmpTaxAudit] PRIMARY KEY NONCLUSTERED 
(
    [ClientID] ASC,
    [EmpUID] ASC,
    [m_uid] ASC,
    [m_eff_start_date] ASC,
    [ReplacedOn] ASC,
    [ColumnName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
Run Code Online (Sandbox Code Playgroud)

源表EmpTax中的触发代码:

CREATE                trigger [dbo].[trins_EmpTax]
on [dbo].[emptax]
for insert
as
begin
  declare 
    @intRowCount  int,
      @user          varchar(30)

  select @intRowCount = @@RowCount
  IF @intRowCount > 0 
  begin
     select @user = suser_sname()

     insert EmpTaxAudit (Clientid, empuid,m_uid,m_eff_start_date, ColumnName, ReplacedOn, ReplacedBy, OldValue,dblogin,newvalue)
     select Clientid, empuid,m_uid,m_eff_start_date,'taxcode', getdate(),IsNull(userid,@user), '', Left(@user,15),'Added'
        from inserted i
         where m_uid not in (select m_uid from EmpTaxAudit 
                    where clientid = i.clientid  and (newvalue = 'Deleted'
            or newvalue = 'DB-Deleted'
                        or newvalue = 'Added') and  empuid = i.empuid)
       and i.m_eff_end_date is null 

     insert EmpTaxAudit (Clientid, empuid,m_uid,m_eff_start_date, ColumnName, ReplacedOn, ReplacedBy, OldValue,dblogin,newvalue)
     select Clientid, empuid,m_uid,m_eff_start_date,'taxcode', getdate(),IsNull(userid,@user), '', Left(@user,15),'Deleted'
        from inserted i
         where m_uid not in (select m_uid from EmpTaxAudit 
                    where clientid = i.clientid  and (newvalue = 'Deleted'
            or newvalue = 'DB-Deleted'
                        or newvalue = 'Added') and  empuid = i.empuid)
       and i.m_eff_end_date is not null 


  end
end
Run Code Online (Sandbox Code Playgroud)

如何避免Hash Match(Inner Join)的高成本?

谢谢!

Sha*_*ehr -1

第一个批评:我认为 a 不PRIMARY KEY应该包含这么多字段。主键只是一个简单的唯一性标识符。可以说,对于多对多交叉表,您的 PK 中可以有两个字段,尽管我个人总是有一个单字段主键,即使对于这些也是如此。所以我想说你的 PKPK_EmpTaxAudit确实应该被重新定义为唯一索引。

然后我建议添加newvalueINCLUDE该索引的字段:

create unique index IX_EmpTaxAudit(
  [ClientID] ASC,
  [EmpUID] ASC,
  [m_uid] ASC,
  [m_eff_start_date] ASC,
  [ReplacedOn] ASC,
  [ColumnName] ASC
)
include (newvalue)
Run Code Online (Sandbox Code Playgroud)

我怀疑这会给你一个更简洁的执行计划。