Gegebene Tabellen der folgenden allgemeinen Form:
CREATE TABLE Device
(
ID integer PRIMARY KEY
);
CREATE TABLE EventType
(
ID integer PRIMARY KEY,
Name nvarchar(50) NOT NULL
);
CREATE TABLE [Event]
(
ID integer PRIMARY KEY,
[TimeStamp] datetime NOT NULL,
EventTypeID integer NOT NULL REFERENCES EventType,
DeviceID integer NOT NULL REFERENCES Device
);
Der folgende Index ist nützlich:
CREATE INDEX f1
ON [Event] ([TimeStamp], EventTypeID)
INCLUDE (DeviceID)
WHERE EventTypeID IN (2, 5, 7, 8, 9, 14);
Für die Abfrage:
SELECT
[Event].ID,
[Event].[TimeStamp],
EventType.Name,
Device.ID
FROM
[Event]
INNER JOIN EventType ON EventType.ID = [Event].EventTypeID
INNER JOIN Device ON Device.ID = [Event].DeviceID
WHERE
[Event].[TimeStamp] BETWEEN '2011-01-28' AND '2011-01-29'
AND Event.EventTypeID IN (2, 5, 7, 8, 9, 14);
Der Filter erfüllt die AND
Klauselanforderung, der erste Schlüssel des Index ermöglicht eine Suche [TimeStamp]
nach dem gefilterten EventTypeIDs
und einschließlich der DeviceID
Spalte das Index-Covering (da DeviceID
dies für den Join zur Device
Tabelle erforderlich ist ).
Der zweite Schlüssel des Index EventTypeID
ist nicht unbedingt erforderlich (es kann sich auch um eine INCLUDEd
Spalte handeln). Ich habe es enthalten im Schlüssel für die hier genannten Gründe . Im Allgemeinen rate ich Leuten, zumindest INCLUDE
Spalten aus einer gefilterten WHERE
Indexklausel zu verwenden.
Aufgrund des aktualisierten Abfrage- und Ausführungsplans in der Frage stimme ich zu, dass der von SSMS vorgeschlagene allgemeinere Index wahrscheinlich die bessere Wahl ist, es sei denn, die gefilterte Liste EventTypeIDs
ist statisch, wie Aaron auch in seiner Antwort erwähnt:
CREATE TABLE Device
(
ID integer PRIMARY KEY,
Name nvarchar(50) NOT NULL UNIQUE
);
CREATE TABLE EventType
(
ID integer PRIMARY KEY,
Name nvarchar(20) NOT NULL UNIQUE,
[Description] nvarchar(100) NOT NULL
);
CREATE TABLE [Event]
(
ID integer PRIMARY KEY,
PLCTimeStamp datetime NOT NULL,
EventTypeID integer NOT NULL REFERENCES EventType,
DeviceID integer NOT NULL REFERENCES Device,
IATA varchar(50) NOT NULL,
Data1 integer NULL,
Data2 integer NULL,
);
Vorgeschlagener Index (deklarieren Sie ihn als eindeutig, falls dies angemessen ist):
CREATE UNIQUE INDEX uq1
ON [Event]
(EventTypeID, PLCTimeStamp)
INCLUDE
(DeviceID, IATA, Data1, Data2, ID);
Kardinalitätsinformationen aus dem Ausführungsplan (undokumentierte Syntax, nicht in Produktionssystemen verwenden):
UPDATE STATISTICS dbo.Event WITH ROWCOUNT = 4042700, PAGECOUNT = 400000;
UPDATE STATISTICS dbo.EventType WITH ROWCOUNT = 22, PAGECOUNT = 1;
UPDATE STATISTICS dbo.Device WITH ROWCOUNT = 2806, PAGECOUNT = 28;
Aktualisierte Abfrage (Wiederholung der IN
Liste für dieEventType
Tabelle hilft dem Optimierer in diesem speziellen Fall):
SELECT
Event.ID,
Event.IATA,
Device.Name,
EventType.Description,
Event.Data1,
Event.Data2,
Event.PLCTimeStamp,
Event.EventTypeID
FROM
Event
INNER JOIN EventType ON EventType.ID = Event.EventTypeID
INNER JOIN Device ON Device.ID = Event.DeviceID
WHERE
Event.EventTypeID IN (3, 30, 40, 41, 42, 46, 49, 50)
AND EventType.ID IN (3, 30, 40, 41, 42, 46, 49, 50)
AND Event.PLCTimeStamp BETWEEN '2011-01-28' AND '2011-01-29'
AND Event.IATA LIKE '%0005836217%'
ORDER BY Event.ID;
Geschätzter Ausführungsplan:
Der Plan, den Sie erhalten, wird wahrscheinlich anders sein, weil ich erratene Statistiken verwende. Der allgemeine Punkt ist, dem Optimierer so viele Informationen wie möglich zu geben und eine effiziente Zugriffsmethode (Index) für die 4-Millionen-Zeilentabelle bereitzustellen [Event]
.