O código de exemplo neste item de conexão
Mostra um bug onde
SELECT COUNT(*)
FROM dbo.my_splitter_1('2') L1
INNER JOIN dbo.my_splitter_1('') L2
ON L1.csv_item = L2.csv_item
Retorna os resultados corretos. Mas o seguinte retorna resultados incorretos (em 2014 usando o novo Estimador de Cardinalidade)
SELECT
(SELECT COUNT(*)
FROM dbo.my_splitter_1('2') L1
INNER JOIN dbo.my_splitter_1('') L2
ON L1.csv_item = L2.csv_item)
Como ele carrega incorretamente os resultados para L2 em um spool de subexpressão comum, reproduz o resultado disso para o resultado L1.
Fiquei curioso para saber por que a diferença de comportamento entre as duas consultas. O Trace Flag 8675 mostra que o que funciona entra search(0) - transaction processing
e o que falha entra search(1) - quick plan
.
Portanto, presumo que a disponibilidade de regras de transformação adicionais esteja por trás da diferença de comportamento (desativar BuildGbApply ou GenGbApplySimple parece corrigi-lo, por exemplo).
Mas por que os dois planos para essas consultas tão semelhantes encontram diferentes fases de otimização? Pelo que li search (0)
requer pelo menos três tabelas e essa condição certamente não é atendida no primeiro exemplo.
Cada estágio tem condições de entrada. "Ter pelo menos três referências de tabela" é uma das condições de entrada de que falamos ao dar exemplos simples, mas não é a única.
Geralmente, apenas junções e uniões básicas são permitidas para entrada para pesquisar 0; subconsultas escalares, semijunções, etc. impedem a entrada para pesquisa 0. Este estágio é realmente para as formas de consulta do tipo OLTP muito comuns. As regras necessárias para explorar as coisas menos comuns simplesmente não estão habilitadas. Sua consulta de exemplo tem uma subconsulta escalar, portanto, falha na entrada.
Também depende de como você conta as referências de tabela. Nunca examinei profundamente isso com funções, mas é possível que a lógica esteja contando as funções com valor de tabela, bem como as variáveis de tabela que elas produzem. Pode até estar contando a referência da tabela dentro da própria função - não tenho certeza; embora eu saiba que as funções são apenas um trabalho árduo.
O bug com
GenGbApplySimple
é feio. Esse formato de plano sempre foi uma possibilidade, mas foi rejeitado por razões de custo até que a mudança para cardinalidade variável de tabela assumida de 100 linhas entrou. É possível forçar o formato de plano problemático no CE anterior a 2014 com umaUSE PLAN
dica, por exemplo.Você está correto sobre o novo item Connect ser o mesmo problema relatado anteriormente .
Para fornecer um exemplo, a consulta a seguir se qualifica para pesquisa 0:
Fazer uma pequena alteração para incluir uma subconsulta escalar significa que ela vai direto para a pesquisa 1: