Eu tenho um problema no SQL Server em que uma busca de índice NONCLUSTERED está tendo um desempenho insatisfatório.
Abaixo está o plano de execução real https://www.brentozar.com/pastetheplan/?id=Sk3-4JGAK
Como posso melhorar o desempenho?
Abaixo está a definição da tabela
CREATE TABLE [Parts].[ManufacturingData](
[LeadFinishId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[PartID] [int] NOT NULL,
[LeadFinishMaterial] [varchar](50) NULL,
[CreatedDate] [datetime] NULL,
[CreatedBy] [int] NULL,
[ModifiedDate] [datetime] NULL,
[Modifiedby] [int] NULL,
[DeletedDate] [datetime] NULL,
[DeletedBy] [int] NULL,
[Revision_Id] [int] NULL,
[BaseMaterialID] [int] NULL,
[MSLID] [int] NULL,
[MSLSource_Revision_id] [int] NULL,
[MaximumReflowTemperatureID] [int] NULL,
[ReflowTemperatureSource_Revision_Id] [int] NULL,
[MaximumWaveTemperatureID] [int] NULL,
[WaveTemperatureSource_Revision_ID] [int] NULL,
[ReflowSolderTimeID] [int] NULL,
[WaveSolderTimeID] [int] NULL,
[NumberOfReflowCycleID] [int] NULL,
[LeadFinishPlatingID] [int] NULL,
[Comment] [varchar](100) NULL,
[LeadfinishSourceTypeID] [int] NULL,
[MSlSourceTypeID] [int] NULL,
[ReflowTemperatureSourceTypeID] [int] NULL,
[BasedOnID] [int] NULL,
[LeadFreeProcessCapabilityID] [int] NULL,
[BaseMaterialRevisionID] [int] NULL,
[BaseMaterialSourceTypeID] [int] NULL,
[UnderplatingRevisionID] [int] NULL,
[UnderplatingSourceTypeID] [int] NULL,
[ShelfLifeCondition] [int] NULL,
CONSTRAINT [PK_PartID] PRIMARY KEY CLUSTERED
(
[PartID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
) ON [Customer]
GO
SET ANSI_PADDING ON
GO
index seek used as below
CREATE NONCLUSTERED INDEX [IDX_MSLID] ON [Parts].[ManufacturingData]
(
[MSLID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
USE [Z2DataCore]
GO
ALTER TABLE [Parts].[ManufacturingData] ADD CONSTRAINT [PK_PartID] PRIMARY KEY CLUSTERED
(
[PartID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
Eu estaria interessado no número de linhas totais que você tem em sua
Parts.ManufacturingData
tabela e qual é o tempo de execução total atualmente para sua consulta. O número de linhas que o plano de execução diz que está retornando (aproximadamente 32 milhões) realmente faz sentido para sua consulta?Talvez você descubra que um índice filtrado economiza um pouco de tempo, pois pré-materializa apenas os dados que você deseja. Que tal um índice com essa definição, faz alguma diferença?
Observe que você não precisa fazer nada diferente em sua consulta para usar o índice filtrado acima depois de criado. Mas você deve verificar o plano de execução para garantir que o otimizador escolheu esse novo índice em relação a quaisquer outros índices em sua tabela quando a consulta for executada.
Se isso não fizer diferença, a outra coisa que você pode tentar é adicionar a
FORCESCAN
dica à sua consulta assim:Isso diria ao otimizador para usar uma operação de varredura em vez de buscar seus dados. Isso geralmente teria melhor desempenho se aproximadamente a maioria dos seus dados na tabela atendesse aos critérios de sua
WHERE
cláusula. Ou seja, geralmente é mais rápido varrer toda a tabela nesse ponto e filtrar as linhas indesejadas, do que procurar em tantas linhas. Mas é difícil dizer se isso ajudará suas circunstâncias sem conhecer seus dados ou testá-los.Observe que as dicas de consulta devem ser usadas com cautela e somente em circunstâncias em que métodos alternativos de otimização não são possíveis. Algumas dicas de consulta limitam o número de planos de execução disponíveis que o otimizador pode escolher e, portanto, podem resultar em um erro quando determinadas consultas que usam essas dicas tentam ser executadas.
Nesse caso, acho que usar a
FORCESCAN
dica provavelmente está ok, pois sua consulta é simples e não acredito que ela limite o número de planos de consulta tanto quanto outras dicas.Talvez você possa tentar com um índice columnstore não clusterizado nos mesmos campos. Isso pode levar a um modo de lote e compactação para que você possa poupar algo na leitura.
documento da microsoft
exemplo:
Sua busca de índice está retornando 32 milhões de linhas. Você tem um bom plano, isso é apenas um monte de dados para ler.
Você pode considerar criar explicitamente a tabela de destino antes de tentar inseri-la.
Além de outras respostas certas, você também pode tentar um método alternativo para melhorar o desempenho, que pode ser criar uma exibição indexada como abaixo:
Depois de criar a visualização acima, crie o índice conforme abaixo:
Após a criação da visualização e do índice acima, você pode reescrever sua consulta como:
Estou alterando a consulta para
insert into
em vez deselect * into
reutilização de código. No caso deselect into
, você sempre precisa descartar a tabela subjacente.Por favor, deixe-nos saber se isso ajuda.