J'ai une structure de base de données similaire à celle-ci,
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
Le point de la table DispatchLink est de lier deux enregistrements Dispatch ensemble. Soit dit en passant, j'utilise une clé primaire composite sur ma table de répartition en raison de l'héritage, donc je ne peux pas changer cela sans trop de peine. De plus, la table des liens n'est peut-être pas la bonne façon de le faire? Mais encore une fois l'héritage.
Donc ma question, si je lance cette requête
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
Je n'arrive jamais à le faire faire une recherche d'index sur la table DispatchLink. Il effectue toujours une analyse complète de l'index. C'est très bien avec quelques enregistrements, mais lorsque vous avez 50000 dans cette table, il analyse 50000 enregistrements dans l'index selon le plan de requête. C'est parce qu'il y a des «et» et des «ou» dans la clause join, mais je ne peux pas comprendre pourquoi SQL ne peut pas faire quelques recherches d'index à la place, une pour le côté gauche du «ou», et un pour le côté droit du «ou».
Je voudrais une explication à cela, pas une suggestion pour accélérer la requête, sauf si cela peut être fait sans ajuster la requête. La raison en est que j'utilise la requête ci-dessus comme filtre de jointure de réplication de fusion, donc je ne peux pas simplement ajouter un autre type de requête malheureusement.
MISE À JOUR: Par exemple, ce sont les types d'index que j'ai ajoutés,
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)
Il utilise donc les index, mais effectue une analyse d'index sur l'ensemble de l'index, donc 50000 enregistrements, il analyse 50000 enregistrements dans l'index.
DispatchLink
table?Réponses:
L'optimiseur peut prendre en compte de nombreuses alternatives de plan (y compris celles avec plusieurs recherches) mais pour les disjonctions (
OR
prédicats), il ne prend pas en compte les plans impliquant des intersections d'index par défaut. Compte tenu des indices:Nous pouvons forcer la recherche d'index (en supposant que SQL Server 2008 ou version ultérieure):
En utilisant vos données d'échantillonnage, le plan de recherche coûte 0,0332551 unités par rapport à 0,0068057 pour le plan de numérisation:
Il existe toutes sortes de réécritures de requêtes et d'indices possibles que nous pouvons essayer. Un exemple de réécriture pour promouvoir une option que l'optimiseur ne prend pas en compte pour le plan d'origine est:
Ce plan d'exécution ne cherche pas le deuxième index s'il trouve une correspondance sur le premier:
Cela peut fonctionner très légèrement mieux que le
FORCESEEK
plan par défaut .Sans ajouter de nouveaux index, nous pouvons également forcer une recherche dans la table Dispatch:
Cela peut être meilleur ou pire que le premier exemple en fonction de choses comme le nombre de lignes dans chacune des tables. L'
APPLY + TOP
amélioration est toujours possible:la source