AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 301557
Accepted
Pantea
Pantea
Asked: 2021-10-24 05:48:11 +0800 CST2021-10-24 05:48:11 +0800 CST 2021-10-24 05:48:11 +0800 CST

O uso inadequado de operadores lógicos levou a um desempenho de consulta ruim

  • 772

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

sql-server query-performance
  • 3 3 respostas
  • 1758 Views

3 respostas

  • Voted
  1. Best Answer
    Andriy M
    2021-10-24T18:23:19+08:002021-10-24T18:23:19+08:00

    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, e b, que podem ou não ser iguais a 0. Escreva e execute uma consulta como esta:

    SELECT
      a
    , b
    , [a!=1 or (a=1 and b!=0)] = CASE WHEN a!=1 or (a=1 and b!=0) THEN 'True' ELSE 'False' END
    , [not (a=1 and b=0)]      = CASE WHEN not (a=1 and b=0)      THEN 'True' ELSE 'False' END
    FROM
      (
        VALUES
          (   1,    0)
        , (   1, 9999)
        , (9999,    0)
        , (9999, 9999)
      ) AS v (a, b)
    ;
    

    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 com a, e "não 0" quando se trata de b. (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:

    uma b a!=1 ou (a=1 e b!=0) não (a=1 eb=0)
    1 0 Falso Falso
    1 9999 Verdadeiro Verdadeiro
    9999 0 Verdadeiro Verdadeiro
    9999 9999 Verdadeiro Verdadeiro

    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 afor anulável e for realmente um nulo, então a=1(ou a!=1para 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:

    SELECT
      a
    , b
    , [a!=1 or (a=1 and b!=0)] = CASE
                                   WHEN      a!=1 or (a=1 and b!=0)  THEN 'True'
                                   WHEN NOT (a!=1 or (a=1 and b!=0)) THEN 'False'
                                   ELSE 'Unknown'
                                 END
    , [not (a=1 and b=0)]      = CASE
                                   WHEN      not (a=1 and b=0)       THEN 'True'
                                   WHEN NOT (not (a=1 and b=0)     ) THEN 'False'
                                   ELSE 'Unknown'
                                 END
    FROM
      (
        VALUES
          (   1,    0)
        , (   1, 9999)
        , (   1, NULL)
        , (9999,    0)
        , (9999, 9999)
        , (9999, NULL)
        , (NULL,    0)
        , (NULL, 9999)
        , (NULL, NULL)
      ) AS v (a, b)
    ;
    

    E dá a seguinte saída:

    uma b a!=1 ou (a=1 e b!=0) não (a=1 eb=0)
    1 0 Falso Falso
    1 9999 Verdadeiro Verdadeiro
    1 nulo Desconhecido Desconhecido
    9999 0 Verdadeiro Verdadeiro
    9999 9999 Verdadeiro Verdadeiro
    9999 nulo Verdadeiro Verdadeiro
    nulo 0 Desconhecido Desconhecido
    nulo 9999 Desconhecido Verdadeiro
    nulo nulo Desconhecido Desconhecido

    Destacado acima está o cenário em que as duas condições não produzem os mesmos resultados, que é quando aé nulo e bé 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 apode ser nulo e, sob essa suposição, suas duas expressões lógicas não são equivalentes. Mas se, por exemplo, só bpuder ser nulo e anã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:

    • Tabela verdade
    • Lógica de três valores
    • 25
  2. Denis Rubashkin
    2021-10-24T06:20:35+08:002021-10-24T06:20:35+08:00

    A condição not (a=1 and b=0)é igual a a!=1 or b!=0que obviamente não é igual aa!=0 or (a=1 and b!=0)

    Por exemplo:

    a = 0
    b = 0
    
    a!=0 or (a=1 and b!=0) => false or (false and false) => false
    
    not (a=1 and b=0) => not (false and true) => true
    
    • 4
  3. J.D.
    2021-10-24T06:12:07+08:002021-10-24T06:12:07+08:00

    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 onde anão for igual 0serão retornados. Isso incluiria registros where a = 1 and b = 0(isso se deve especificamente ao uso de uma ORcláusula). Seu segundo predicado reescrito where 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 ORcláusulas podem ser reescritas de forma mais eficiente UNIONentre os dois lados da cláusula em uma consulta separada. Por exemplo:

    SELECT ...
    FROM test
    WHERE a!=0 
    
    UNION
    
    SELECT ...
    FROM test
    WHERE a=1 and b!=0
    

    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.

    • 3

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve