Tenho uma tabela com grande quantidade de dados (quase 15 milhões) e estrutura abaixo.
create table test
(a int,--> /* There is a normal index on this column */
b int,
<other columns>)
Há uma consulta selecionando desta tabela e uma das condições na cláusula where é esta:
where a!=1 or (a=1 and b!=0) /* The original condition */
A consulta estava muito lenta e achei que a maior parte desse desempenho ruim poderia ser por causa do uso indevido de operadores lógicos. Eu mudei a condição como você vê abaixo:
where not (a=1 and b=0) /* The edited version*/
e o desempenho mudou drasticamente! O que eu preciso ter certeza é que as duas condições são exatamente as mesmas para que eu não perca nenhum dado. Eu queria saber se você poderia me ajudar com isso e me dizer se você tem alternativas melhores para a condição.
Se você conhece algum artigo sobre o uso correto de operações lógicas e a forma como/otimizador de ordens as tratam, por favor, compartilhe o link.
desde já, obrigado
Para descobrir se duas condições são realmente equivalentes, você pode tentar construir a tabela verdade para cada uma delas e ver se as duas tabelas são idênticas.
Aqui está como você pode construir as tabelas-verdade. Você tem duas variáveis,
a
, que podem ou não ser iguais a 1, eb
, que podem ou não ser iguais a 0. Escreva e execute uma consulta como esta:Para cada variável, especifique o valor com o qual a variável é comparada, para que uma comparação correspondente seja verdadeira ou falsa (dependendo de ser
=
ou!=
), e outro valor que produza o resultado oposto. O valor 9999 acima é apenas um valor arbitrário que significa "não 1" quando se trata de comparações coma
, e "não 0" quando se trata deb
. (Fui com algo completamente diferente de 1 ou 0 para não tornar a tabela resultante muito confusa.)A consulta acima retornará a seguinte saída:
Como você pode ver, ambas as expressões fornecem resultados idênticos para valores de entrada idênticos.
Observe, no entanto, que a tabela acima contém apenas valores que fazem as comparações serem avaliadas como True ou False . É assim que as coisas normalmente são na álgebra booleana. No entanto, no mundo SQL, uma expressão booleana pode ser avaliada para um terceiro estado, Unknown , também conhecido como Null . Se
a
for anulável e for realmente um nulo, entãoa=1
(oua!=1
para esse assunto) será avaliado como Unknown / Null . Se a nulidade precisar ser considerada, nossas tabelas-verdade devem incluir nulos como valores de entrada.Aqui está uma versão modificada do script acima que inclui nulos para ambas as variáveis:
E dá a seguinte saída:
Destacado acima está o cenário em que as duas condições não produzem os mesmos resultados, que é quando
a
é nulo eb
é um valor não nulo que não é 0. Nesse caso, o resultado da primeira condição é desconhecido enquanto o da outra é verdadeiro.Novamente, isso supõe que
a
pode ser nulo e, sob essa suposição, suas duas expressões lógicas não são equivalentes. Mas se, por exemplo, sób
puder ser nulo ea
não puder, você poderá ver na saída acima que os resultados nas linhas correspondentes são idênticos.Você encontrará sua resposta, portanto, com base na nulidade das variáveis envolvidas.
Alguns links para mais leitura:
A condição
not (a=1 and b=0)
é igual aa!=1 or b!=0
que obviamente não é igual aa!=0 or (a=1 and b!=0)
Por exemplo:
Infelizmente, não acho que sua reescrita seja logicamente equivalente. Em seu primeiro predicado você tem o
where a != 0 or ...
que significa que quaisquer registros ondea
não for igual0
serão retornados. Isso incluiria registroswhere a = 1 and b = 0
(isso se deve especificamente ao uso de umaOR
cláusula). Seu segundo predicado reescritowhere not (a = 1 and b = 0)
excluiria esse mesmo caso.Mas você deve ser capaz de testar isso comparando as contagens de linhas de ambos os predicados, para verificar. Se necessário, você pode criar uma pequena tabela temporária com cada combinação de valores que está testando (por exemplo
(a,b) = {(0,0), (0,1), (1,0), (1,1)}
, ) e, em seguida, aplicar cada predicado para ver o resultado.Uma dica que posso oferecer é que, às vezes, as
OR
cláusulas podem ser reescritas de forma mais eficienteUNION
entre os dois lados da cláusula em uma consulta separada. Por exemplo:Dependendo de seus índices e predicados, isso pode permitir que um índice seja procurado com eficiência. Embora eu não tenha certeza se isso ajudaria no seu caso ao usar um operador de desigualdade como
!=
.Mas fora isso, para sugestões de melhoria de desempenho, provavelmente precisaríamos ver seu plano de execução.