Étant donné les tableaux de la forme générale suivante:
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
);
L'index suivant est utile:
CREATE INDEX f1 
ON [Event] ([TimeStamp], EventTypeID) 
INCLUDE (DeviceID)
WHERE EventTypeID IN (2, 5, 7, 8, 9, 14);
Pour la requête:
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);
Le filtre répond à l' ANDexigence de la clause, la première clé de l'index permet une recherche sur [TimeStamp]le filtré EventTypeIDset l'inclusion de la DeviceIDcolonne rend l'index couvrant (car il DeviceIDest requis pour la jointure à la Devicetable).

La deuxième clé de l'index - EventTypeIDn'est pas strictement requise (il peut également s'agir d'une INCLUDEdcolonne); Je l'ai inclus dans la clé pour les raisons indiquées ici . En général, je conseille aux gens d'au moins des INCLUDEcolonnes d'une WHEREclause d' index filtré .
Sur la base de la mise à jour de la requête et du plan d'exécution dans la question, je conviens que l'index plus général suggéré par SSMS est probablement le meilleur choix ici, à moins que la liste des filtrés ne EventTypeIDssoit statique comme Aaron le mentionne également dans sa réponse:
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,
);
Index suggéré (le déclarer unique si cela est approprié):
CREATE UNIQUE INDEX uq1
ON [Event]
    (EventTypeID, PLCTimeStamp)
INCLUDE 
    (DeviceID, IATA, Data1, Data2, ID);
Informations de cardinalité du plan d'exécution (syntaxe non documentée, ne pas utiliser dans les systèmes de production):
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;
Requête mise à jour (la répétition de la INliste pour la EventTypetable aide l'optimiseur dans ce cas spécifique):
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;
Plan d'exécution estimé:

Le plan que vous obtiendrez sera probablement différent, car j'utilise des statistiques devinées. L'idée générale est de fournir à l'optimiseur autant d'informations que possible et de fournir une méthode d'accès efficace (index) sur la [Event]table de 4 millions de lignes .