Tenho a seguinte consulta SQL:
declare @p1 INT = 20240703;
declare @p2 INT = 20240703;
declare @p3 NVARCHAR(50) = N'USA';
SELECT R.taxareaid, R.filtertypes
FROM region R
JOIN country C ON R.countryid = C.countryid
where C.name = @p3
and R.effdate <= @p1 AND R.expdate >= @p2
ORDER BY R.taxareaid
OPTION (RECOMPILE);
https://www.brentozar.com/pastetheplan/?id=B1FTNkXHkx
CREATE TABLE [dbo].[Region](
[regionId] [numeric](18, 0) NOT NULL,
[taxAreaId] [numeric](18, 0) NOT NULL,
[effDate] [numeric](8, 0) NOT NULL,
[expDate] [numeric](8, 0) NOT NULL,
[countryId] [numeric](18, 0) NOT NULL,
[mainDivisionId] [numeric](18, 0) NOT NULL,
[subDivisionId] [numeric](18, 0) NOT NULL,
[cityId] [numeric](18, 0) NOT NULL,
[postalCodeId] [numeric](18, 0) NOT NULL,
[cityCompressedId] [numeric](18, 0) NOT NULL,
[subDivCompressedId] [numeric](18, 0) NOT NULL,
[filterTypes] [numeric](32, 0) NOT NULL,
[updateId] [numeric](18, 0) NOT NULL,
CONSTRAINT pk_region PRIMARY KEY CLUSTERED
(
[regionId] ASC
)
Problema:
Estimativas do Plano de Execução : Quando olho para o plano de execução, percebo que as estimativas são muito menores do que as linhas realmente processadas. Embora eu esteja usando
OPTION (RECOMPILE)
para evitar a detecção de parâmetros, ainda não estou obtendo estimativas precisas. Também atualizei as estatísticas naregion
tabela usando uma varredura completa, mas as estimativas ainda estão incorretas.Vazamento no TempDB : a consulta está causando um vazamento no TempDB durante a classificação.
O que eu tentei:
- Estatísticas atualizadas : executei uma verificação completa para atualizar as estatísticas na
region
tabela. - Índices : criei um índice em
region(taxareaid)
e um índice composto em(countryid, effdate, expdate, taxareaid)
, mas ainda estou vendo classificação no plano de execução.
Minhas perguntas:
- Como posso obter estimativas mais precisas do plano de execução para evitar o vazamento do TempDB durante a classificação?
- Como posso evitar a operação de classificação completamente? Existem outras estratégias que eu possa tentar, já que a indexação não parece resolver o problema?
Para fazer literalmente o que é pedido na pergunta, você precisa destes dois índices secundários (e nenhum outro):
Corrigindo os tipos de dados das variáveis para corresponder à tabela:
O plano é:
O índice exclusivo no país é necessário para garantir que a pesquisa de nome produza no máximo uma linha.
O índice em Região permite uma busca em countryId , retornando linhas na ordem taxAreaId .
Isso é o máximo que podemos fazer com um índice b-tree não filtrado. Os outros predicados em effDate e expDate não podem ser usados para buscar enquanto também preservam a ordem taxAreaId . Então, esses dois predicados serão aplicados como testes residuais em todas as linhas que correspondem ao countryId .
Você pode ou não achar que esse plano tem um desempenho melhor na prática do que aquele com a classificação.
Observe que você não precisa da
RECOMPILE
dica acima. As estimativas de cardinalidade podem ou não ser melhores. Elas não importam para esse formato de plano. Você parece sempre querer que os loops aninhados sejam aplicados e nenhuma classificação. Nada depende da estimativa de cardinalidade da tabela Region.Faz pouco sentido usar
numeric
como o tipo de dados para todas as colunas em uma tabela, especialmente aquelas que presumivelmente armazenam datas. Você nem sempre verá um aviso de conversão de tipo porque o SQL Server se esforça para projetar uma busca mesmo quando o programador foi desleixado com os tipos de dados. Mas essas são questões separadas sobre as quais você não perguntou.Você pode tentar reescrever a consulta fatorando a parte que seleciona
countryid
em uma consulta separada. Isso pode ajudar a melhorar as estimativas de cardinalidade:Para evitar a classificação, crie um índice com
taxAreaId
a coluna-chave principal:Criei tabelas e inseri alguns dados fictícios. A consulta reescrita que fatora o countryid selecionado como uma consulta separada produziu estatísticas precisas com sucesso, e o otimizador selecionou IX_taxAreaId, que eliminou a classificação, como a escolha ótima para o plano de consulta. Portanto, no meu caso, manterei esse índice e excluirei o outro.
No entanto, sua distribuição de dados pode ser diferente. Por favor, deixe-me saber como isso funciona com seus dados!