Ich führe den Ausführungsplan für die folgende Abfrage aus:
select m_uid from EmpTaxAudit
where clientid = 91682
and empuid = 42100176452603
and newvalue in('Deleted','DB-Deleted','Added')
Hier ist der Ausführungsplan:
Ich habe einen nicht gruppierten Index für die EmpTaxAudit-Tabelle für ClientId- und NewValue-Spalten, der oben als 14,9% der Ausführung angezeigt wird:
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)
Ich habe auch eine nicht gruppierte eindeutige Index-PK wie folgt:
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)
Triggercode in der Quelltabelle 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
Was kann ich tun, um die hohen Kosten für Hash Match (Inner Join) zu vermeiden?
Vielen Dank!
sql-server
execution-plan
tuning
Adolfo Perez
quelle
quelle
Antworten:
Für die erste Abfrage wäre ein Index, der alle drei Spalten aus der
WHERE
Klausel verwendet und die Spalte aus derSELECT
Liste enthält, viel nützlicher:oder ein Index, der speziell für diese Abfrage bestimmt ist:
In Bezug auf den Auslöser einige Kommentare:
inserted
Zeilen zu einer anderen Tabelle (die den Auslöser hat).Der Trigger hat 2 fast identische
insert
Anweisungen. Warum? Ich denke, sie könnten in einer - und einfacheren - Einfügung und Verwendung kombiniert werden,NOT EXISTS
anstattNOT IN
:quelle
Grund für Hash Match (innerer Join):
Ihre kleinere Tabelle gibt also eindeutig 16 Zeilen zurück, und Ihre größere Tabelle gibt 1,41.000 Zeilen zurück. Hier ist eine kleinere Tabelle ein Hash, was ziemlich gut ist. Jetzt wird sie mit 1,41.000 Zeilen verbunden, sodass die Kosten höher und die Ausführungszeit langsam sein müssen.
Sie müssen die Anzahl der Zeilen, die in einer großen Tabelle zurückgegeben werden, minimieren. In beiden Fällen erhalten Sie eine Indexsuche, damit der Index verwendet wird.
Ich denke, Sie müssen nur die Trigger-Abfrage neu schreiben.
Beachten Sie, dass Sie den Zustand innerhalb der
NOT EXISTS
Klausel korrigieren können , die geringfügig ist. Sie können jedoch perfekt funktionieren und eine bessere Leistung erzielen.Erklären Sie auch, was der Clustered-Index in dieser Tabelle ist und warum so viele zusammengesetzte Primärschlüssel.
quelle
Erste Kritik: Ich denke nicht, dass a
PRIMARY KEY
aus so vielen Feldern bestehen sollte. Ein Primärschlüssel soll lediglich eine einfache Kennung der Eindeutigkeit sein. Möglicherweise könnten Sie zwei Felder in Ihrer PK für viele-zu-viele Schnittpunkttabellen haben, obwohl ich persönlich immer einen Primärschlüssel mit einem Feld habe, auch für diese. Daher würde ich sagen, dass Ihre PKPK_EmpTaxAudit
wirklich als eindeutiger Index neu definiert werden sollte.Dann würde ich vorschlagen, hinzuzufügen
newvalue
zu denINCLUDE
Feldern dieses Index :Ich vermute, das wird Ihnen einen übersichtlicheren Ausführungsplan geben.
quelle
Zunächst sollten Sie einen Clustered-Index (mit FILLFACTOR <= 95) für die Tabellen haben, um hohe E / A-Vorgänge zu vermeiden. Weil HEAP zu mehr Fragmentierung führt. Sie können also PK Non Clustered Index durch Clustered ersetzen.
Abgesehen davon sollten zur Vermeidung von HASH_MATCH alle in der SELECT-Anweisung verwendeten Spalten vorhanden sein und die WHERE-Klausel sollte sich in einem Index befinden. Entweder ersetzen Sie den nicht gruppierten Index idx_EmpTaxAudit_clientid_newvalue durch den folgenden oder erstellen einen neuen nicht gruppierten Index.
Grund von HASH_MATCH
SQL Server Optimizer bevorzugt die Verwendung von Index anstelle von HEAP. In Ihrem Fall werden also Daten und Spalten angefordert, in denen die Bedingung auf zwei verschiedenen Indizes liegt. Aus diesem Grund hat SQL Server Optimizer beide Indizes verwendet und HASH_MATCH ausgeführt.
Vielen Dank
quelle