IN vs OR na cláusula SQL WHERE

150

Ao lidar com grandes bancos de dados, qual é o melhor desempenho INou ORna Wherecláusula SQL ?

Existe alguma diferença na maneira como eles são executados?

felix
fonte
Meu primeiro palpite seria que OU tenha um desempenho melhor, a menos que o mecanismo SQL converta IN em OU nos bastidores. Você já viu o plano de consulta desses dois?
Raj
Possível duplicata do desempenho
Steve Chambers

Respostas:

170

Suponho que você queira saber a diferença de desempenho entre os seguintes:

WHERE foo IN ('a', 'b', 'c')
WHERE foo = 'a' OR foo = 'b' OR foo = 'c'

De acordo com o manual do MySQL, se os valores são constantes, INclassifica a lista e, em seguida, usa uma pesquisa binária. Eu imagino que os ORavalie um por um em nenhuma ordem particular. Então, INé mais rápido em algumas circunstâncias.

A melhor maneira de saber é criar um perfil tanto no seu banco de dados com dados específicos para ver qual é mais rápido.

Eu tentei ambos em um MySQL com 1000000 linhas. Quando a coluna é indexada, não há diferença perceptível no desempenho - ambas são quase instantâneas. Quando a coluna não está indexada, obtive estes resultados:

SELECT COUNT(*) FROM t_inner WHERE val IN (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
1 row fetched in 0.0032 (1.2679 seconds)

SELECT COUNT(*) FROM t_inner WHERE val = 1000 OR val = 2000 OR val = 3000 OR val = 4000 OR val = 5000 OR val = 6000 OR val = 7000 OR val = 8000 OR val = 9000;
1 row fetched in 0.0026 (1.7385 seconds)

Portanto, neste caso, o método usando OR é cerca de 30% mais lento. Adicionar mais termos aumenta a diferença. Os resultados podem variar em outros bancos de dados e em outros dados.

Mark Byers
fonte
20
Se o otimizador vale seu sal, ele deve executar o mesmo.
Janick Bernet
27
@inflagranti: Infelizmente, nenhum otimizador é perfeito. Otimizadores são programas extremamente complexos e cada implementação terá seus próprios pontos fortes e fracos. É por isso que digo que você deve criar um perfil em uma implementação específica. Eu imagino que a estrutura extra do INmétodo facilite a otimização do que várias ORcláusulas possivelmente relacionadas . Eu ficaria surpreso se houver um mecanismo em que o ORmétodo seja mais rápido, mas não estou surpreso que haja momentos em que OU seja mais lento.
Mark Byers
2
@ MarkByers O otimizador não poderia sempre substituir vários ORs por um IN?
precisa saber é
36

A melhor maneira de descobrir é examinar o plano de execução.


Eu tentei com o Oracle e era exatamente o mesmo.

CREATE TABLE performance_test AS ( SELECT * FROM dba_objects );

SELECT * FROM performance_test
WHERE object_name IN ('DBMS_STANDARD', 'DBMS_REGISTRY', 'DBMS_LOB' );

Mesmo que a consulta use IN, o Plano de Execução diz que usa OR:

--------------------------------------------------------------------------------------    
| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |    
--------------------------------------------------------------------------------------    
|   0 | SELECT STATEMENT  |                  |     8 |  1416 |   163   (2)| 00:00:02 |    
|*  1 |  TABLE ACCESS FULL| PERFORMANCE_TEST |     8 |  1416 |   163   (2)| 00:00:02 |    
--------------------------------------------------------------------------------------    

Predicate Information (identified by operation id):                                       
---------------------------------------------------                                       

   1 - filter("OBJECT_NAME"='DBMS_LOB' OR "OBJECT_NAME"='DBMS_REGISTRY' OR                
              "OBJECT_NAME"='DBMS_STANDARD')                                              
Peter Lang
fonte
1
O que acontece no Oracle se você tiver mais de 3 valores que está testando? Você sabe se o Oracle não consegue executar a mesma otimização de pesquisa binária que o MySQL ou executa nos dois casos?
Mark Byers
2
@ Mark Byers: Eu tentei a mesma consulta com 10 valores, ainda o mesmo resultado. Observe que o otimizador utilizou meus valores em ordem alfabética. Eu não ficaria surpreso se a Oracle fez alguma otimização interna desse filtro ...
Peter Lang
5
A Oracle também possui uma INLIST ITERATORoperação, que selecionaria se houvesse um índice que pudesse usar. Ainda assim, quando eu tentei sair, tanto INe ORacabam com o mesmo plano de execução.
Cheran Shunmugavel
7

O operador OR precisa de um processo de avaliação muito mais complexo que o construto IN, pois permite muitas condições, não apenas iguais a IN.

Aqui está um exemplo do que você pode usar com OU, mas que não é compatível com IN: maior. maior ou igual, menor, menor ou igual, LIKE e mais parecido com o oracle REGEXP_LIKE. Além disso, considere que as condições nem sempre podem comparar o mesmo valor.

Para o otimizador de consultas, é mais fácil gerenciar o operador IN porque é apenas uma construção que define o operador OR em várias condições com o operador = no mesmo valor. Se você usar o operador OR, o otimizador poderá não considerar que você está sempre usando o operador = no mesmo valor e, se ele não executar uma elaboração mais profunda e muito mais complexa, provavelmente poderá excluir que possa haver apenas = operadores para os mesmos valores em todas as condições envolvidas, com uma conseqüente exclusão de métodos de pesquisa otimizados, como a pesquisa binária já mencionada.

[EDIT] Provavelmente, um otimizador pode não implementar o processo de avaliação IN otimizado, mas isso não exclui que uma vez isso poderia acontecer (com uma atualização da versão do banco de dados). Portanto, se você usar o operador OR, a elaboração otimizada não será usada no seu caso.

Alessandro Rossi
fonte
6

Eu acho que o oracle é inteligente o suficiente para converter o menos eficiente (o que for) para o outro. Então eu acho que a resposta deve depender da legibilidade de cada um (onde eu acho que INclaramente vence)

soulmerge
fonte
2

ORfaz sentido (do ponto de vista da legibilidade), quando há menos valores a serem comparados. INé útil esp. quando você tem uma fonte dinâmica, com a qual deseja comparar valores.

Outra alternativa é usar a JOINcom uma tabela temporária.
Não acho que o desempenho deva ser um problema, desde que você tenha os índices necessários.

shahkalpesh
fonte
-2

Eu fiz uma consulta SQL em um grande número de OR (350). O Postgres faz isso 437.80ms .

Use OR

Agora use IN:

Use IN

23.18ms

user3003962
fonte
4
Isso não é exatamente a mesma coisa, já que você usou uma subconsulta para a cláusula IN.
gliljas