Criei uma função que aceita data inicial e final, sendo a data final opcional. Em seguida, escrevi um CASE
no filtro para usar a data de início se nenhuma data de término for passada.
CASE WHEN @dateEnd IS NULL
THEN @dateStart
ELSE @dateEnd
END
Quando eu chamo a função para o mês mais recente dos dados:
SELECT * FROM theFunction ('2013-06-01', NULL)
... a consulta trava. Se eu especificar a data final:
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
... o resultado é retornado normalmente. Tirei o código da função e executei-o bem dentro de uma janela de consulta. Também não consigo duplicar o problema no violino. Uma consulta como:
SELECT * FROM theFunction ('2013-04-01', '2013-06-01')
... também funciona bem.
Existe alguma coisa na consulta (abaixo) que pode estar causando o travamento da função quando um NULL
é passado para a data final?
- Plano de execução para
SELECT * FROM theFunction ('2013-06-01', '2013-06-01')
- Plano estimado para
SELECT * FROM theFunction ('2013-06-01', NULL)
Parte de sua consulta inicial é a seguinte.
Essa seção do plano é mostrada abaixo
Sua consulta revisada
BETWEEN @dateStart AND ISNULL(@dateEnd,@dateStart)
tem isso para a mesma junçãoA diferença parece ser que
ISNULL
simplifica ainda mais e, como resultado, você obtém estatísticas de cardinalidade mais precisas indo para a próxima junção. Esta é uma função com valor de tabela embutida e você a está chamando com valores literais para que ela possa fazer algo como.E como há um predicado de junção equi
b.[Date] = a.d
, o plano também mostra um predicado de igualdadeb.[Date] = '2013-06-01'
. Como resultado, a estimativa de cardinalidade das28,393
linhas provavelmente será bastante precisa.Para a versão
CASE
/COALESCE
quando@dateStart
e@dateEnd
são o mesmo valor, simplifica OK para a mesma expressão de igualdade e fornece o mesmo plano, mas quando@dateStart = '2013-06-01'
e@dateEnd IS NULL
só vai atéque também se aplica como um predicado implícito em
ColleagueList
. O número estimado de linhas desta vez é79.8
linhas.A próxima junção é
colleagueTime
é uma3,249,590
tabela de linhas que é (novamente) aparentemente uma pilha sem índices úteis.Essa discrepância nas estimativas afeta a escolha de união usada. O
ISNULL
plano escolhe uma junção de hash que verifica a tabela apenas uma vez. OCOALESCE
plano escolhe uma junção de loops aninhados e estima que ainda precisará apenas escanear a tabela uma vez e ser capaz de processar o resultado e reproduzi-lo 78 vezes. ou seja, estima que os parâmetros correlacionados não serão alterados.Pelo fato de que o plano de loops aninhados ainda estava em andamento após duas horas, essa suposição de uma única verificação
colleagueTime
parece ser altamente imprecisa.Quanto ao motivo pelo qual o número estimado de linhas entre as duas junções é muito menor, não tenho certeza sem poder ver as estatísticas nas tabelas. A única maneira de distorcer tanto as contagens de linhas estimadas em meus testes foi adicionando uma carga de
NULL
linhas (isso reduziu a contagem de linhas estimadas, embora o número real de linhas retornadas permanecesse o mesmo).A contagem de linhas estimada no
COALESCE
plano com meus dados de teste estava na ordem deOu em SQL
mas isso não condiz com seu comentário de que a coluna não tem
NULL
valores.Parece que houve um problema com os tipos de dados.
ISNULL
corrigiu o problema (obrigado ypercube ). Depois de algumas pesquisas,COALESCE
é o equivalente àCASE
declaração que eu estava usando:Paulo White explica que:
Para evitar problemas de tipo de dados, parece
ISNULL
ser a função apropriada a ser usada para lidar com apenas duas expressões.Trechos do Plano XML
plano XML usando
CASE
, a expressão 2 éNULL
:Plano XML usando
CASE
, a expressão 2 é uma data:plano XML usando
ISNULL
, a expressão 2 éNULL
:Plano XML usando
ISNULL
, a expressão 2 é uma data: