As expressões booleanas nas cláusulas SQL WHERE são avaliadas em curto-circuito ?
Por exemplo:
SELECT *
FROM Table t
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key)
Se @key IS NULL for avaliado como true, @key IS NOT NULL AND @key = t.Key é avaliada?
Se não, por que não?
Se sim, é garantido? Faz parte do ANSI SQL ou é específico do banco de dados?
Se for específico do banco de dados, SqlServer? Oráculo? MySQL?
sql
short-circuiting
Greg Dean
fonte
fonte
WHERE a = 1 AND b = 2
poderia ser eficiente para o mecanismo de banco de dados encontrar todas as linhas onde b = 2 primeiro, depois filtre onde a = 1. Se você pedir garantia, o otimizador se tornará inútil.Respostas:
ANSI SQL Draft 2003 5WD-01-Framework-2003-09.pdf
fonte
CASE
está em curto-circuito.Pelo exposto, o curto-circuito não está realmente disponível.
Se você precisar, sugiro uma declaração de caso:
Expr1
é sempre avaliado, mas apenas umExpr2
eExpr3
será avaliado por linha.fonte
Eu acho que esse é um dos casos em que eu escreveria como se não tivesse um curto-circuito, por três razões.
Porque para o MSSQL, isso não é resolvido olhando para o BOL no lugar óbvio, então, para mim, isso o torna canonicamente ambíguo.
porque pelo menos sei que meu código funcionará. E o mais importante, os que vierem atrás de mim também, então eu não os prepararei para se preocupar com a mesma pergunta repetidamente.
Escrevo com bastante frequência para vários produtos DBMS e não quero lembrar das diferenças para poder contorná-las facilmente.
fonte
Não acredito que seja garantido um curto-circuito no SQL Server (2005). O SQL Server executa sua consulta através do algoritmo de otimização que leva em consideração várias coisas (índices, estatísticas, tamanho da tabela, recursos etc.) para criar um plano de execução eficaz. Após essa avaliação, você não pode ter certeza de que sua lógica de curto-circuito está garantida.
Encontrei a mesma pergunta há algum tempo e minha pesquisa realmente não me deu uma resposta definitiva. Você pode escrever uma pequena consulta para dar uma prova de que funciona, mas pode ter certeza de que, à medida que a carga no banco de dados aumenta, as tabelas aumentam e as coisas são otimizadas e alteradas no banco de dados, essa conclusão será aguarde. Não pude e, portanto, errei por precaução e usei a cláusula CASE in WHERE para garantir um curto-circuito.
fonte
Você deve ter em mente como os bancos de dados funcionam. Dada uma consulta parametrizada, o db cria um plano de execução com base nessa consulta sem os valores para os parâmetros. Essa consulta é usada sempre que a consulta é executada, independentemente dos valores reais fornecidos. Se o curto-circuito da consulta com determinados valores não importará para o plano de execução.
fonte
Eu normalmente uso isso para parâmetros opcionais. É o mesmo que curto-circuito?
Isso me dá a opção de passar -1 ou o que quer que seja responsável pela verificação opcional de um atributo. Às vezes, isso envolve a junção em várias tabelas ou, de preferência, uma visualização.
Muito útil, sem ter certeza do trabalho extra que ele oferece ao mecanismo db.
fonte
Para o SQL Server, acho que depende da versão, mas minha experiência com o SQL Server 2000 é que ele ainda avalia @key = t.Key mesmo quando @key é nulo. Em outras palavras, ele não produz um curto-circuito eficiente ao avaliar a cláusula WHERE.
Eu já vi pessoas recomendando uma estrutura como o seu exemplo como uma maneira de fazer uma consulta flexível na qual o usuário pode inserir ou não inserir vários critérios. Minha observação é que Key ainda está envolvido no plano de consulta quando @key é nulo e se Key é indexado, ele não usa o índice com eficiência.
Esse tipo de consulta flexível com critérios variados é provavelmente um caso em que o SQL criado dinamicamente é realmente o melhor caminho a percorrer. Se @key for nulo, você simplesmente não o inclui na consulta.
fonte
Acabei de tropeçar nessa pergunta e já havia encontrado esta entrada no blog: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/
O servidor SQL é livre para otimizar uma consulta em qualquer lugar que ela achar conveniente; portanto, no exemplo dado na postagem do blog, você não pode confiar em curto-circuito.
No entanto, um CASE aparentemente está documentado para avaliar na ordem por escrito - verifique os comentários dessa publicação no blog.
fonte
A principal característica da avaliação de curto-circuito é que ela para de avaliar a expressão assim que o resultado pode ser determinado. Isso significa que o restante da expressão pode ser ignorado porque o resultado será o mesmo, independentemente de ser avaliado ou não.
Operadores booleanos binários são alternativos, o que significa:
portanto, não há garantia na ordem da avaliação. A ordem da avaliação será determinada pelo otimizador de consulta.
Em linguagens com objetos, pode haver situações em que você pode escrever expressões booleanas que podem ser avaliadas apenas com a avaliação de curto-circuito. Sua construção de código de exemplo é frequentemente usada nesses idiomas (C #, Delphi, VB). Por exemplo:
Este exemplo de C # causará exceção se
someString == null
porque será totalmente avaliado. Na avaliação de curto-circuito, funcionará sempre.O SQL opera apenas em variáveis escalares (sem objetos) que não podem ser inicializados, portanto, não há como gravar expressões booleanas que não possam ser avaliadas. Se você tiver algum valor NULL, qualquer comparação retornará false.
Isso significa que no SQL você não pode escrever expressões que sejam avaliadas diferentemente, dependendo do uso de curto-circuito ou avaliação completa.
Se a implementação do SQL usar avaliação de curto-circuito, esperamos que isso acelere a execução da consulta.
fonte
eu não sei sobre curto-circuito, mas eu escreveria isso como uma declaração if-else
Além disso, as variáveis devem sempre estar no lado direito da equação. isso o torna sargável.
http://en.wikipedia.org/wiki/Sargable
fonte
Abaixo um teste rápido e sujo no SQL Server 2008 R2:
Isso retorna imediatamente sem registros. Tipo de comportamento de curto-circuito estava presente.
Então tentei o seguinte:
sabendo que nenhum registro satisfaria esta condição:
Isso levou vários segundos, indicando que o comportamento do curto-circuito não existia mais e a operação complexa estava sendo avaliada para cada registro.
Espero que isso ajude caras.
fonte
Aqui está uma demonstração para provar que o MySQL executa um curto-circuito na cláusula WHERE :
http://rextester.com/GVE4880
Isso executa as seguintes consultas:
A única diferença entre eles é a ordem dos operandos na condição OR.
myslowfunction
deliberadamente dorme por um segundo e tem o efeito colateral de adicionar uma entrada a uma tabela de logs sempre que for executada. Aqui estão os resultados do que é registrado ao executar as duas consultas acima:A descrição acima mostra que uma função lenta é executada mais vezes quando aparece no lado esquerdo de uma condição OR quando o outro operando nem sempre é verdadeiro (devido a curto-circuito).
fonte
Isso leva mais 4 segundos no analisador de consultas, portanto, pelo que posso ver, SE nem sequer está em curto ...
Seria bom ter uma maneira garantida!
fonte
É óbvio que o servidor MS Sql suporta a teoria de curto-circuito, para melhorar o desempenho, evitando verificações desnecessárias,
Exemplo de suporte:
Aqui, o primeiro exemplo resultaria no erro 'Falha na conversão ao converter o valor varchar' A 'para o tipo de dados int'.
Enquanto a segunda é executada facilmente, a condição 1 = 1 é avaliada como TRUE e, portanto, a segunda condição não é executada.
Além disso
aqui a primeira condição seria avaliada como falsa e, portanto, o DBMS passaria para a segunda condição e, novamente, você receberá o erro de conversão como no exemplo acima.
OBSERVAÇÃO: ESCREVA A CONDIÇÃO ERRÔNICA APENAS PARA REALIZAR O TEMPO QUE A CONDIÇÃO É EXECUTADA OU CURTA CIRCUITO SE RESULTADOS QUERIDOS EM ERRO SIGNIFICAM A CONDIÇÃO EXECUTADA E CURTA CIRCUITO DE OUTRA FORMA.
EXPLICAÇÃO SIMPLES
Considerar,
pois a primeira condição está sendo avaliada como TRUE , não faz sentido avaliar a segunda condição porque sua avaliação em qualquer valor não afetaria o resultado, portanto, é uma boa oportunidade para o Sql Server economizar tempo de execução de consulta ignorando a verificação ou avaliação desnecessária da condição .
no caso de "OR", se a primeira condição for avaliada como VERDADEIRA, toda a cadeia conectada por "OR" será considerada como verdadeira sem avaliar outras.
se a condição1 for avaliada como verdadeira, descanse todas as condições até que a condiçãoN seja ignorada. Em palavras generalizadas na determinação do primeiro TRUE , todas as outras condições vinculadas por OR seriam ignoradas.
Considere a segunda condição
como a primeira condição está sendo avaliada para FALSE avaliada não faz sentido avaliar a segunda condição, porque sua avaliação em qualquer valor não afetaria o resultado; novamente, é uma boa oportunidade para o Sql Server economizar o tempo de execução da consulta ignorando a verificação ou avaliação desnecessária da condição .
no caso de "AND", se a primeira condição for avaliada como FALSE, toda a cadeia conectada com o "AND" seria considerada avaliada como FALSE sem avaliar outras.
se a condição1 for avaliada como FALSE , descanse todas as condições até que a condiçãoN seja ignorada. Em palavras generalizadas na determinação do primeiro FALSE , todas as outras condições vinculadas por AND seriam ignoradas.
Portanto, um programador sábio sempre deve programar a cadeia de condições de uma maneira que, menos dispendiosa ou a maioria das condições de eliminação, seja avaliada em primeiro lugar ou altere a condição de uma maneira que possa tirar o máximo benefício de curto-circuito
fonte