Existe uma maneira de 'injetar' uma estimativa de cardinalidade em um otimizador do SQL Server (qualquer versão)?
ou seja, algo semelhante à dica de cardinalidade do Oracle.
Minha motivação é impulsionada pelo artigo Quão bons são os otimizadores de consulta, realmente? [1] , onde testam a influência do estimador de cardinalidade na seleção de um plano ruim. Portanto, seria suficiente se eu pudesse forçar o SQL Server a 'estimar' as cardinalidades precisamente para consultas complexas.
[1] Leis, Victor, et al. "Quão bons são os otimizadores de consulta, realmente?"
Anais do Fundo VLDB 9.3 (2015): 204-215.
Você pode obter algo semelhante à
CARDINALITY
dica da Oracle usando estrategicamenteTOP
e uma função definida pelo usuário chamadaMANY()
desenvolvida por Adam Machanic . Vamos trabalhar com alguns exemplos. Estou usando o banco de dados AdventureWorks disponível gratuitamente. Suponha que eu realmente precise controlar o número de linhas retornadas pelath
tabela derivada na seguinte consulta:Como está, recebo uma estimativa de 113443 linhas:
Se eu precisar diminuir a estimativa
th
, posso usarTOP
junto com aOPTIMIZE FOR
dica de consulta para definir uma meta de linha. Aqui está uma maneira de fazer isso:Podemos ver que a estimativa é apenas 1 linha:
Eu defini
@row_goal
para o maiorBIGINT
valor possível para evitar alterar os resultados. AOPTIMIZE FOR
dica de consulta instrui o otimizador a otimizar a consulta como se@row_goal
fosse igual a 1. Obterei os mesmos resultados, mas a consulta será otimizada de maneira diferente.Aumentar uma estimativa de cardinalidade é mais complicado. Não podemos simplesmente aumentar o valor de
TOP
porque o otimizador perceberá que não retornará linhas suficientes. No entanto, podemos usar aMANY()
função para adicionar linhas à estimativa. Observe que aMANY()
função sempre retornará 0 linhas, mas a estimativa de linha dela muda com o parâmetro de entrada. Suponha que você precise aumentar a estimativa de linha da tabela derivada em 10 vezes. Uma maneira de conseguir isso:Podemos ver que a estimativa é 10X a tabela base:
O supérfluo
TOP
foi adicionado para evitar que o otimizador mova as tabelas. Sem ela, aMANY()
função pode ser aplicada no lugar errado do plano.É possível combinar as duas técnicas se você quiser uma superestimativa precisa em vez de apenas multiplicar o número de linhas por um fator. Por exemplo, vamos supor que você realmente precise que a estimativa da tabela derivada seja exatamente 1.000.000 linhas. Uma maneira de conseguir isso:
Podemos ver que a estimativa é de 1.000.000 linhas:
Preciso avisá-lo de que essas são técnicas avançadas que geralmente não são necessárias para a otimização de consultas. Se você quiser saber mais eu recomendo assistir Clash of the Row Goals apresentado por Adam Machanic.
função dbo.Many
Não há como injetar uma estimativa de cardinalidade diretamente no otimizador, mas dependendo do que você deseja alcançar, existem algumas opções.
Você pode usar uma
OPTION (FAST N)
dica de consulta para introduzir metas de linha e possivelmente reescrever sua consulta usando CTEs ou subconsultas para injetarTOP...ORDER BY
metas de linha baseadas em diferentes partes do seu plano de execução, mas não tenho certeza de quão eficiente será sua consulta resultante quando você iniciar brincando com as construções mais complexas.Consulte Por Dentro do Otimizador: Objetivos de Linha em Profundidade para obter uma explicação mais completa.
Se você quiser influenciar os operadores escolhidos pelo otimizador, não precisará tentar injetar estimativas de cardinalidade, mas poderá usar coisas como
OPTION (MERGE JOIN)
ouOPTION (HASH JOIN)
, por exemplo, para forçar operadores de junção física.Este artigo entra em mais detalhes sobre como influenciar um plano usando dicas: Controlando planos de execução com dicas
Se você deseja corrigir um plano, também pode usar um guia de plano.
Novamente, não está claro qual é o seu caso de uso real, e sua milhagem pode variar usando essas técnicas. Em muitos casos, é melhor deixar o otimizador decidir e certificar-se de que você tenha estatísticas atualizadas para que o otimizador possa tomar uma decisão informada.
Sugestão relevante do Microsoft Connect: permitir especificar a dica de seletividade de filtro em consultas por xor88. A Microsoft respondeu:
Você pode usar a dica de consulta do SQL Server
OPTIMIZE FOR
para forçar a estimativa de cardinalidade com base nos valores sugeridos em vez de usar o valor real (parâmetros) ou o valor desconhecido (variáveis) durante a compilação. Consulte o tópico de dicas de consulta na documentação do SQL Server para obter detalhes completos.Por exemplo, a consulta abaixo estimará as contagens de linhas com base no histograma de estatísticas dos valores sugeridos, em vez da cardinalidade média geral, como faria com variáveis locais.
Da mesma forma, a dica pode ser usada para parâmetros para que as estimativas sejam baseadas no histograma de estatísticas dos valores sugeridos em vez dos valores reais dos parâmetros durante a compilação.
A
UNKNOWN
palavra-chave pode ser especificada em vez de um literal na dica para usar a cardinalidade média geral em vez de estimar com base no valor real do parâmetro e no histograma de estatísticas.