Fiquei com a impressão de que, ao usar o LIKE
operador em todas as otimizações para cenários desconhecidos, tanto o legado quanto os novos CEs usam uma estimativa de 9% (supondo que estatísticas relevantes estejam disponíveis e o otimizador de consulta não precise recorrer a suposições de seletividade).
Ao executar a consulta abaixo no banco de dados de crédito, obtenho diferentes estimativas nos diferentes CEs. Sob o novo CE, recebo uma estimativa de 900 linhas que eu esperava, sob o CE herdado, recebo uma estimativa de 241,416 e não consigo descobrir como essa estimativa é derivada. Alguém é capaz de lançar alguma luz?
-- New CE (Estimate = 900)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName;
-- Forcing Legacy CE (Estimate = 241.416)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName
OPTION (
QUERYTRACEON 9481,
QUERYTRACEON 9292,
QUERYTRACEON 9204,
QUERYTRACEON 3604
);
No meu cenário, já tenho o banco de dados de crédito definido para o nível de compatibilidade 120, por isso na segunda consulta estou usando sinalizadores de rastreamento para forçar o CE herdado e também para fornecer informações sobre quais estatísticas são usadas/consideradas pelo otimizador de consulta. Posso ver que as estatísticas da coluna 'sobrenome' estão sendo usadas, mas ainda não consigo descobrir como a estimativa de 241,416 é derivada.
Não consegui encontrar nada on-line além deste artigo de Itzik Ben-Gan , que afirma "Ao usar o predicado LIKE em todas as otimizações para cenários desconhecidos, tanto o legado quanto os novos CEs usam uma estimativa de 9 por cento". As informações nesse post parecem estar incorretas.
O palpite para
LIKE
o seu caso é baseado em:G
: O palpite padrão de 9% (sqllang!x_Selectivity_Like
)M
: Um fator de 6 (número mágico)D
: Comprimento médio dos dados em bytes (de estatísticas), arredondado para número inteiroEspecificamente,
sqllang!CCardUtilSQL7::ProbLikeGuess
usa:Notas:
LOG(D)
termo é omitido seD
estiver entre 1 e 2.D
for menor que 1 (incluindo falta ouNULL
estatísticas):D = FLOOR(0.5 * maximum column byte length)
Esse tipo de estranheza e complexidade é bastante típico do CE original.
No exemplo da pergunta, o comprimento médio é 5 (5,6154 de
DBCC SHOW_STATISTICS
arredondado para baixo):Outros valores de exemplo:
Equipamento de teste
Testei no SQL Server 2014 com o CE legado e também não obtive 9% como estimativa de cardinalidade. Não consegui encontrar nada preciso online, então fiz alguns testes e encontrei um modelo que se encaixa em todos os casos de teste que tentei, mas não tenho certeza se está completo.
No modelo que encontrei, a estimativa é derivada do número de linhas na tabela, o tamanho médio da chave das estatísticas para a coluna filtrada e, às vezes, o tamanho do tipo de dados da coluna filtrada. Existem duas fórmulas diferentes usadas para a estimativa.
Se FLOOR(comprimento médio da chave) = 0, a fórmula de estimativa ignora as estatísticas da coluna e cria uma estimativa com base no comprimento do tipo de dados. Eu testei apenas com VARCHAR(N), então é possível que haja uma fórmula diferente para NVARCHAR(N). Aqui está a fórmula para VARCHAR(N):
Isso tem um ajuste muito bom, mas não é perfeitamente preciso:
O eixo x é o comprimento do tipo de dados e o eixo y é o número de linhas estimadas para uma tabela com 1 milhão de linhas.
O otimizador de consulta usaria essa fórmula se você não tivesse estatísticas na coluna ou se a coluna tivesse valores NULL suficientes para direcionar o comprimento médio da chave para menos de 1.
Por exemplo, suponha que você tenha uma tabela com 150k linhas com filtragem em VARCHAR(50) e nenhuma estatística de coluna. A previsão de estimativa de linha é:
SQL para testar:
O SQL Server fornece uma contagem de linha estimada de 7242,47, que é quase fechada.
Se FLOOR(comprimento médio da chave) >= 1, uma fórmula diferente é usada com base no valor de FLOOR(comprimento médio da chave). Aqui está uma tabela de alguns dos valores que eu tentei:
Se FLOOR(tamanho médio da chave) < 6, use a tabela acima. Caso contrário, use a seguinte equação:
Este tem um ajuste melhor do que o outro, mas ainda não é perfeitamente preciso.
O eixo x é o comprimento médio da chave e o eixo y é o número de linhas estimadas para uma tabela com 1 milhão de linhas.
Para dar outro exemplo, suponha que você tenha uma tabela com 10 mil linhas com um comprimento médio de chave de 5,5 para as estatísticas na coluna filtrada. A estimativa de linha seria:
SQL para testar:
A estimativa de linha é 241.416, que corresponde ao que você tem na pergunta. Haveria algum erro se eu usasse um valor que não estivesse na tabela.
Os modelos aqui não são perfeitos, mas acho que ilustram muito bem o comportamento geral.