Pergunta

Eu estou querendo saber o que o desempenho de uma consulta seria como usar a palavra-chave LIKE e o curinga como o valor em comparação com não ter onde cláusula em tudo.

Considere uma cláusula WHERE, como "WHERE a LIKE '%'". Isso irá corresponder a todos os possíveis valores da coluna 'a'. Como isso se compara a não ter a cláusula onde em tudo.

A razão que eu peço é que eu tenho um aplicativo onde existem alguns campos que o usuário pode especificar valores para a pesquisa. Em alguns casos, o usuário gostaria todos os resultados possíveis. Atualmente, estou usando uma única consulta como esta:

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Os valores de '%' e '%' pode ser fornecido para corresponder todos os valores possíveis para uma e ou b. Isto é conveniente desde que eu posso usar uma única consulta nomeada no meu aplicativo para isso. Eu me pergunto o que as considerações de desempenho são para isso. Será que o otimizador de consulta reduzir LIKE '%' simplesmente corresponder a todos? Sei que porque eu estou usando uma consulta nomeada (declaração preparada), que também pode afetar a resposta. Sei que a resposta é específico do banco de dados provável. Então, especificamente como isso funcionaria na Oracle, MS SQL Server e Derby.

A abordagem alternativa para isso seria usar 3 consultas separadas com base no usuário introduzir o curinga.

A é consulta wildcard:

SELECT * FROM TableName WHERE b LIKE ?

B é consulta wildcard:

SELECT * FROM TableName WHERE a LIKE ?

A e B são curingas:

SELECT * FROM TableName

Não wildcards:

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Obviamente, ter uma única consulta é o mais simples e mais fácil de manter. Eu prefiro usar apenas uma consulta se o desempenho ainda vai ser bom.

Foi útil?

Solução 3

Eu estava esperando que seria um livro didático resposta a isso, mas parece que ele será em grande parte variar de acordo com diferentes tipos de banco de dados. A maioria das respostas indicaram que eu deveria executar um teste de modo que é exatamente o que eu fiz.

Meu aplicativo tem como alvo principalmente os bancos de dados do Derby, MS SQL e Oracle. Desde derby pode ser executado embutido e é fácil de configurar, eu testei o desempenho nesse primeiro. Os resultados foram surpreendentes. Eu testei o pior cenário contra uma bastante grande mesa. Eu corri o teste de 1000 vezes e em média os resultados.

Consulta 1:

SELECT * FROM TableName

Consulta 2 (Com valores de a = "%" e b = "%"):

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

Consulta 1 tempo médio: 178ms

Consulta 2 tempo médio: 181ms

Assim, o desempenho no derby é quase a mesma entre as duas consultas.

Outras dicas

SQL Server geralmente verá

WHERE City LIKE 'A%'

e tratá-lo como

WHERE City >= 'A' AND City < 'B'

... e feliz usar um índice procuram se for o caso. Eu digo 'geral', porque eu vi que não conseguem fazer esta simplificação em certos casos.

Se alguém está tentando fazer:

WHERE City LIKE '%ville'

... então uma busca de índice será essencialmente impossível.

Mas algo tão simples como:

WHERE City LIKE '%'

será considerada equivalente a:

WHERE City IS NOT NULL

Você pode usar qualquer análise de consulta do SGBD ofertas (por exemplo EXPLAIN para MySQL, SET SHOWPLAN_ALL ON para MS SQL (ou o uso um dos outros métodos ), EXPLAIN PLAN FOR para Oracle ) para ver como a consulta será executada.

Qualquer DBMS vale o seu sal seria retirar cláusulas LIKE '%' antes mesmo de tentar para executar a consulta. Estou bastante certo de que eu vi DB2 / z fazer isso em seus planos de execução.

A declaração preparada não deve fazer a diferença, uma vez que deve ser transformado em real SQL antes que ele chegue ao motor de execução.

Mas, como em todas as questões de otimização, medida, não acho ! existem DBAs porque constantemente ajustar os DBMS com base em dados reais (que muda ao longo do tempo). No mínimo, você deve tempo (e obter os planos de execução) para todas as variações com dados estáticos adequados para ver se há uma diferença.

Eu sei que as consultas como:

select c from t where ((1 = 1) or (c = ?))

são otimizado para remover toda a cláusula WHERE antes da execução (no DB2 de qualquer maneira e, antes que você pergunte, a construção é útil quando você precisa remover o efeito da cláusula onde, mas ainda manter o parâmetro espaço reservado (usando BIRT com Javascript para modificar as consultas para wildcards)).

Derby também oferece ferramentas para examinar o plano de consulta real que foi usado, então você pode executar experimentos usando Derby e olhar para o plano de consulta que Derby escolheu. Você pode executar o Derby com -Dderby.language.logQueryPlan = true e Derby vai escrever o plano de consulta no arquivo derby.log, ou você pode usar o recurso runtimestatistics, como descrito aqui: http://db.apache.org/derby/docs/10.5/tuning/ctundepth853133.html

Eu não tenho certeza se Derby irá retirar o A LIKE '%' antes do tempo, mas eu também não acho que a presença dessa cláusula irá apresentar muito de uma desaceleração da velocidade de execução.

Eu estaria muito interessado em ver a saída plano de consulta real que você recebe em seu ambiente, com e sem '%' cláusula do A como no lugar.

A Oracle 10gR2 não aparecer para executar uma otimização especial para esta situação, mas reconhece que LIKE '%' exclui nulos.

create table like_test (col1)
as select cast(dbms_random.string('U',10) as varchar2(10))
from dual
connect by level <= 1000
/
insert into like_test values (null)
/
commit
/

exec dbms_stats.gather_table_stats(user,'like_test')

explain plan for
select count(*)
from   like_test
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 like '%'
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 is not null
/
select plan_table_output from table(dbms_xplan.display)
/

... dar ...

Plan hash value: 3733279756

------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Cost (%CPU)| Time     |
------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |            |          |
|   2 |   TABLE ACCESS FULL| LIKE_TEST |  1001 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------

... e ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

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

   2 - filter("COL1" LIKE '%')

... e ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

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

   2 - filter("COL1" IS NOT NULL)

Observe a cardinalidade (linhas) na linha completa Tabela ACCESS

Dependendo de como o predicado LIKE é estruturado e no campo que você está testando, você pode precisar de uma varredura completa da tabela. Semanticamente um '%' pode implicar uma varredura completa da tabela, mas Sql Server faz todos os tipos de otimização internamente nas consultas. Portanto, a questão torna-se:? Otimizar O SQL Server em um predicado LIKE formado com '%' e joga-o para fora da cláusula WHERE

Um aspecto que eu acho que está faltando a partir da discussão é o fato de que o OP quer usar uma declaração preparada. Na época, a instrução é preparada, o banco de dados / otimizador não será capaz de trabalhar as simplificações outros já mencionados e, portanto, não será capaz de otimizar afastado o a like '%' como o valor real não será conhecido em preparar tempo.

Por isso:

  • ao usar declarações preparadas, têm quatro declarações diferentes disponíveis (0, apenas uma, única B, ambos) e usar o mais adequado quando necessário
  • veja se você obter um melhor desempenho quando você não usar uma declaração preparada quando adere a apenas uma declaração (embora, então seria muito fácil para não incluir condições 'vazio')

E se uma coluna tem um valor em branco não-nulo? Sua consulta provavelmente irá corresponder-lo.

Se esta é uma consulta para uma aplicação no mundo real, em seguida, tente usar a indexação de texto livre caracteriza da maioria dos bancos de dados SQL modernos. Os problemas de desempenho se tornará insignificante.

A simples declaração se de se (A B) procurar a b outra (A) procurar um outra B Pesquisa b outro dizer utilizador eles não especificar nada

é trivial para manter e se torna muito mais fácil de entender em vez de fazer suposições sobre o operador LIKE. Você provavelmente vai fazer isso na interface do usuário de qualquer maneira quando você exibir os resultados "sua busca por um encontrado x" ou "Sua busca por A B encontrado ..."

Eu não tenho certeza do valor de usar uma declaração preparada com o tipo de parâmetros que você está descrevendo. A razão é que você pode enganar o otimizador de consulta para preparar um plano de execução que seria completamente errado, dependendo de qual dos parâmetros foram '%'.

Por exemplo, se a instrução foram preparadas com um plano de execução usando o índice na coluna A, mas o parâmetro para a coluna A acabou por ser '%' poderá detectar um fraco desempenho.

uma cláusula onde, com "like '%'" como o único predicado vai se comportar exatamente o mesmo que nenhum onde cláusula em tudo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top