Encontramos um problema interessante com o SQL Server. Considere o seguinte exemplo de reprodução:
CREATE TABLE #test (s_guid uniqueidentifier PRIMARY KEY);
INSERT INTO #test (s_guid) VALUES ('7E28EFF8-A80A-45E4-BFE0-C13989D69618');
SELECT s_guid FROM #test
WHERE s_guid = '7E28EFF8-A80A-45E4-BFE0-C13989D69618'
AND s_guid <> NEWID();
DROP TABLE #test;
Por favor, esqueça por um momento que a s_guid <> NEWID()
condição parece totalmente inútil - este é apenas um exemplo mínimo de reprodução. Como a probabilidade de NEWID()
corresponder a um determinado valor constante é extremamente pequena, ela deve ser avaliada como TRUE sempre.
Mas isso não acontece. A execução dessa consulta geralmente retorna 1 linha, mas às vezes (com bastante frequência, mais de 1 vez em cada 10) retorna 0 linhas. Eu o reproduzi com o SQL Server 2008 no meu sistema e você pode reproduzi-lo on-line com o violino vinculado acima (SQL Server 2014).
Examinar o plano de execução revela que o analisador de consultas aparentemente divide a condição em s_guid < NEWID() OR s_guid > NEWID()
:
... o que explica completamente por que às vezes falha (se o primeiro ID gerado for menor e o segundo maior que o ID fornecido).
O SQL Server pode avaliar A <> B
como A < B OR A > B
, mesmo que uma das expressões seja não determinística? Se sim, onde está documentado? Ou encontramos um bug?
Curiosamente, AND NOT (s_guid = NEWID())
produz o mesmo plano de execução (e o mesmo resultado aleatório).
Encontramos esse problema quando um desenvolvedor queria excluir opcionalmente uma linha específica e usou:
s_guid <> ISNULL(@someParameter, NEWID())
como um "atalho" para:
(@someParameter IS NULL OR s_guid <> @someParameter)
Estou procurando documentação e / ou confirmação de um bug. O código não é tão relevante, portanto, as soluções alternativas não são necessárias.
fonte
Respostas:
Este é um ponto um tanto controverso, e a resposta é um "sim" qualificado.
A melhor discussão que eu conheço foi dada em resposta ao relatório de bug do Itzik Ben-Gan do Connect Bug with NEWID e Table Expressions , que foi fechado como não será corrigido. O Connect foi desativado, então o link existe para um arquivo da web. Infelizmente, muito material útil foi perdido (ou dificultado de encontrar) pelo fim do Connect. De qualquer forma, as citações mais úteis de Jim Hogg da Microsoft são:
Um exemplo da mudança de comportamento nesse sentido ao longo do tempo é o NULLIF funciona incorretamente com funções não determinísticas, como RAND () . Também existem outros casos semelhantes usando, por exemplo,
COALESCE
uma subconsulta que pode produzir resultados inesperados e que também estão sendo tratados gradualmente.Jim continua:
Isso é consequência da normalização, que ocorre muito cedo durante a compilação de consultas. Ambas as expressões são compiladas exatamente da mesma forma normalizada, para que o mesmo plano de execução seja produzido.
fonte
Isso está documentado (mais ou menos) aqui:
Funções definidas pelo usuário
Este não é o único formulário de consulta em que o plano de consulta executará NEWID () várias vezes e alterará o resultado. Isso é confuso, mas é realmente crítico que NEWID () seja útil para geração de chave e classificação aleatória.
O mais confuso é que nem todas as funções não determinísticas realmente se comportam assim. Por exemplo, RAND () e GETDATE () serão executados apenas uma vez por consulta.
fonte
=
,<
e>
podem ser eficientemente avaliada contra um BTree.Pelo que vale a pena, se você olhar para este antigo documento padrão do SQL 92 , os requisitos em torno da desigualdade são descritos na seção "
8.2 <comparison predicate>
" da seguinte maneira:Nota: Incluí 7b e 7h para completude, pois eles falam sobre
<>
comparação - não acho que a comparação de construtores de valor de linha com vários valores seja implementada no T-SQL, a menos que eu esteja apenas entendendo mal o que isso diz - o que é bem possívelIsso é um monte de lixo confuso. Mas se você quiser continuar mergulhando no lixo ...
Eu acho que 1.ii é o item que se aplica nesse cenário, pois estamos comparando os valores de "elementos construtores de valor de linha".
Basicamente,
X <> Y
é verdade que os valores representados por X e Y não são iguais. ComoX < Y OR X > Y
é uma reescrita logicamente equivalente desse predicado, é totalmente legal para o otimizador usá-lo.O padrão não impõe nenhuma restrição a essa definição relacionada à determinística (ou seja o que for que você entende) dos elementos construtores do valor da linha em ambos os lados do
<>
operador de comparação. É responsabilidade do código do usuário lidar com o fato de que uma expressão de valor de um lado pode ser não determinística.fonte