Eu tenho uma estrutura de banco de dados semelhante a esta,
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
O objetivo da tabela DispatchLink é vincular dois registros de expedição. A propósito, estou usando uma chave primária composta na minha tabela de expedição por causa do legado, por isso não posso mudar isso sem muita dor. Além disso, a tabela de links pode não ser a maneira correta de fazer isso? Mas novamente legado.
Então, minha pergunta, se eu executar esta consulta
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
Nunca consigo fazer uma busca de índice na tabela DispatchLink. Ele sempre faz uma verificação completa do índice. Isso é bom com alguns registros, mas quando você tem 50000 nessa tabela, ele varre 50000 registros no índice de acordo com o plano de consulta. É porque existem 'ands' e 'ors' na cláusula join, mas não consigo entender por que o SQL não pode fazer algumas buscas de índice, uma para o lado esquerdo da 'ou', e um para o lado direito do 'ou'.
Eu gostaria de uma explicação para isso, não uma sugestão para tornar a consulta mais rápida, a menos que isso possa ser feito sem ajustar a consulta. O motivo é que estou usando a consulta acima como um filtro de junção de replicação de mesclagem, portanto, infelizmente, não posso adicionar outro tipo de consulta.
UPDATE: por exemplo, esses são os tipos de índices que eu adicionei,
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)
Portanto, ele usa os índices, mas faz uma varredura do índice em todo o índice; portanto, 50000 registros, ele varre 50000 registros no índice.
fonte
DispatchLink
cima da mesa?Respostas:
O otimizador pode considerar muitas alternativas de plano (incluindo aquelas com várias buscas), mas para disjunções (
OR
predicados) ele não considera planos que envolvem interseções de índice por padrão. Dados os índices:Podemos forçar buscas de índice (assumindo o SQL Server 2008 ou posterior):
Usando seus dados de amostra, o plano de busca custa 0,0332551 unidades em comparação com 0,0068057 para o plano de varredura:
Existem todos os tipos de reescritas e dicas possíveis que podemos tentar. Um exemplo de reescrita para promover uma opção que o otimizador não considera para o plano original é:
Este plano de execução não procura o segundo índice se encontrar uma correspondência no primeiro:
Isso pode ter um desempenho um pouco melhor que o
FORCESEEK
plano padrão .Sem adicionar novos índices, também podemos forçar uma busca na tabela Dispatch:
Isso pode ser melhor ou pior que o primeiro exemplo, dependendo de coisas como quantas linhas existem em cada uma das tabelas. A
APPLY + TOP
melhoria ainda é possível:fonte