У меня есть структура базы данных, похожая на эту,
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
Задача таблицы DispatchLink - связать две записи Dispatch вместе. Между прочим, я использую составной первичный ключ в своей таблице диспетчеризации из-за устаревшего, поэтому я не могу изменить это без большой боли. Также таблица ссылок не может быть правильным способом сделать это? Но опять наследие.
Так что мой вопрос, если я выполню этот запрос
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
Я никогда не смогу выполнить поиск индекса по таблице DispatchLink. Всегда выполняется полное сканирование индекса. Это хорошо с несколькими записями, но когда у вас есть 50000 в этой таблице, она сканирует 50000 записей в индексе в соответствии с планом запроса. Это потому, что в предложении объединения есть «ands» и «ors», но я не могу понять, почему SQL не может вместо этого выполнить пару поисков индекса, один для левой части «or», и один для правой стороны «или».
Я хотел бы получить объяснение этому, а не предложение ускорить запрос, если это не может быть сделано без корректировки запроса. Причина в том, что я использую приведенный выше запрос в качестве фильтра объединения репликации слиянием, поэтому, к сожалению, я не могу просто добавить другой тип запроса.
ОБНОВЛЕНИЕ: Например, это типы индексов, которые я добавил,
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)
Таким образом, он использует индексы, но выполняет сканирование индекса по всему индексу, поэтому 50000 записей сканирует 50000 записей в индексе.
DispatchLink
столе?Ответы:
Оптимизатор может рассмотреть много вариантов плана (в том числе с несколькими поисками), но для дизъюнкций (
OR
предикатов) он не учитывает планы, включающие пересечения индексов по умолчанию. Учитывая индексы:Мы можем принудительно выполнить поиск индекса (при условии, что SQL Server 2008 или более поздняя версия):
Используя ваши данные выборки, план поиска будет стоить 0,0332551 единиц по сравнению с 0,0068057 для плана сканирования:
Мы можем попробовать все виды переписывания запросов и подсказок. Один пример переписывания для продвижения опции, которую оптимизатор не рассматривает для исходного плана:
Этот план выполнения не ищет второй индекс, если находит совпадение по первому:
Это может работать немного лучше, чем
FORCESEEK
план по умолчанию .Без добавления каких-либо новых индексов мы также можем форсировать поиск в таблице Dispatch:
Это может быть лучше или хуже, чем в первом примере, в зависимости от того, сколько строк в каждой из таблиц.
APPLY + TOP
Улучшение все еще возможно:источник