Ao lidar com grandes bancos de dados, qual é o melhor desempenho IN
ou OR
na Where
cláusula SQL ?
Existe alguma diferença na maneira como eles são executados?
Ao lidar com grandes bancos de dados, qual é o melhor desempenho IN
ou OR
na Where
cláusula SQL ?
Existe alguma diferença na maneira como eles são executados?
Respostas:
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, IN
classifica a lista e, em seguida, usa uma pesquisa binária. Eu imagino que os OR
avalie 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.
IN
método facilite a otimização do que várias OR
cláusulas possivelmente relacionadas . Eu ficaria surpreso se houver um mecanismo em que o OR
método seja mais rápido, mas não estou surpreso que haja momentos em que OU seja mais lento.
OR
s por um IN
?
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')
INLIST ITERATOR
operação, que selecionaria se houvesse um índice que pudesse usar. Ainda assim, quando eu tentei sair, tanto IN
e OR
acabam com o mesmo plano de execução.
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.
OR
faz 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 JOIN
com uma tabela temporária.
Não acho que o desempenho deva ser um problema, desde que você tenha os índices necessários.
Eu fiz uma consulta SQL em um grande número de OR (350). O Postgres faz isso 437.80ms .
Agora use IN:
23.18ms