Ich habe eine ähnliche Datenbankstruktur,
CREATE TABLE [dbo].[Dispatch](
[DispatchId] [int] NOT NULL,
[ContractId] [int] NOT NULL,
[DispatchDescription] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Dispatch] PRIMARY KEY CLUSTERED
(
[DispatchId] ASC,
[ContractId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[DispatchLink](
[ContractLink1] [int] NOT NULL,
[DispatchLink1] [int] NOT NULL,
[ContractLink2] [int] NOT NULL,
[DispatchLink2] [int] NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (1, 1, N'Test')
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (2, 1, N'Test')
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (3, 1, N'Test')
GO
INSERT [dbo].[Dispatch] ([DispatchId], [ContractId], [DispatchDescription]) VALUES (4, 1, N'Test')
GO
INSERT [dbo].[DispatchLink] ([ContractLink1], [DispatchLink1], [ContractLink2], [DispatchLink2]) VALUES (1, 1, 1, 2)
GO
INSERT [dbo].[DispatchLink] ([ContractLink1], [DispatchLink1], [ContractLink2], [DispatchLink2]) VALUES (1, 1, 1, 3)
GO
INSERT [dbo].[DispatchLink] ([ContractLink1], [DispatchLink1], [ContractLink2], [DispatchLink2]) VALUES (1, 3, 1, 2)
GO
Der Zweck der DispatchLink-Tabelle besteht darin, zwei Dispatch-Datensätze miteinander zu verknüpfen. Übrigens verwende ich aufgrund von Legacy einen zusammengesetzten Primärschlüssel für meine Versandtabelle, daher kann ich das nicht ohne große Schmerzen ändern. Auch die Link-Tabelle ist möglicherweise nicht der richtige Weg, dies zu tun? Aber wieder Vermächtnis.
Also meine Frage, ob ich diese Abfrage ausführe
select * from Dispatch d
inner join DispatchLink dl on d.DispatchId = dl.DispatchLink1 and d.ContractId = dl.ContractLink1
or d.DispatchId = dl.DispatchLink2 and d.ContractId = dl.ContractLink2
Ich kann es nie dazu bringen, eine Indexsuche für die DispatchLink-Tabelle durchzuführen. Es wird immer ein vollständiger Index-Scan durchgeführt. Das ist mit ein paar Datensätzen in Ordnung, aber wenn Sie 50000 in dieser Tabelle haben, werden 50000 Datensätze im Index gemäß dem Abfrageplan gescannt. Dies liegt daran, dass die Join-Klausel 'ands' und 'ors' enthält, aber ich kann mir nicht vorstellen, warum SQL nicht stattdessen ein paar Indexsuchen durchführen kann, eine für die linke Seite des 'or'. und eine für die rechte Seite des 'oder'.
Ich möchte eine Erklärung dafür, keinen Vorschlag, die Abfrage schneller zu machen, es sei denn, dies kann ohne Anpassung der Abfrage erfolgen. Der Grund dafür ist, dass ich die obige Abfrage als Filter für die Zusammenführung von Replikationsverknüpfungen verwende, sodass ich leider nicht einfach einen anderen Abfragetyp hinzufügen kann.
UPDATE: Dies sind zum Beispiel die Arten von Indizes, die ich hinzugefügt habe.
CREATE NONCLUSTERED INDEX IDX1 ON DispatchLink (ContractLink1, DispatchLink1)
CREATE NONCLUSTERED INDEX IDX2 ON DispatchLink (ContractLink2, DispatchLink2)
CREATE NONCLUSTERED INDEX IDX3 ON DispatchLink (ContractLink1, DispatchLink1, ContractLink2, DispatchLink2)
Es verwendet also die Indizes, führt jedoch einen Index-Scan über den gesamten Index durch, sodass 50000 Datensätze 50000 Datensätze im Index scannen.
DispatchLink
Tisch?Antworten:
Das Optimierungsprogramm kann viele Planalternativen berücksichtigen (einschließlich solcher mit mehreren Suchvorgängen), bei Disjunktionen (
OR
Prädikaten) werden jedoch standardmäßig keine Pläne mit Indexschnittpunkten berücksichtigt. Angesichts der Indizes:Wir können Indexsuchen erzwingen (vorausgesetzt, SQL Server 2008 oder höher):
Unter Verwendung Ihrer Beispieldaten kostet der Suchplan 0,0332551 Einheiten im Vergleich zu 0,0068057 für den Scanplan :
Es gibt alle möglichen Umschreibungen und Hinweise für Abfragen, die wir ausprobieren können. Ein Beispiel für ein Umschreiben, um eine Option zu fördern, die der Optimierer für den ursprünglichen Plan nicht berücksichtigt, ist:
Dieser Ausführungsplan sucht nicht nach dem zweiten Index, wenn er eine Übereinstimmung mit dem ersten findet:
Dies kann etwas besser als der Standardplan sein
FORCESEEK
.Ohne neue Indizes hinzuzufügen, können wir auch eine Suche in die Dispatch-Tabelle erzwingen:
Dies kann besser oder schlechter sein als das erste Beispiel, abhängig davon, wie viele Zeilen in jeder der Tabellen enthalten sind. Die
APPLY + TOP
Verbesserung ist noch möglich:quelle