Pergunta

Existe alguma diferença no desempenho dos três seguintes instruções SQL?

SELECT * FROM tableA WHERE EXISTS (SELECT * FROM tableB WHERE tableA.x = tableB.y)

SELECT * FROM tableA WHERE EXISTS (SELECT y FROM tableB WHERE tableA.x = tableB.y)

SELECT * FROM tableA WHERE EXISTS (SELECT 1 FROM tableB WHERE tableA.x = tableB.y)

Eles todos devem trabalhar e retornar o mesmo conjunto de resultados. Mas não importa se os seleciona SELECT interna todos os campos da tableB, um campo, ou apenas uma constante?

Existe alguma melhor prática quando todas as declarações comportam igual?

Foi útil?

Solução

A verdade sobre a cláusula EXISTS é que a cláusula SELECT não é avaliada em uma cláusula EXISTS - você pode tentar:

SELECT * 
  FROM tableA 
 WHERE EXISTS (SELECT 1/0 
                 FROM tableB 
                WHERE tableA.x = tableB.y)

... e deve esperar uma divisão por zero erro, mas você não vai porque não é avaliada. É por isso que o meu hábito é especificar NULL em uma existe para demonstrar que o SELECT pode ser ignorado:

SELECT * 
  FROM tableA 
 WHERE EXISTS (SELECT NULL
                 FROM tableB 
                WHERE tableA.x = tableB.y)

Tudo o que importa em uma cláusula EXISTS é a DE e além cláusulas -. WHERE, GROUP BY, HAVING, etc

Esta questão não foi marcado com um banco de dados em mente, e que deve ser porque os vendedores lidar com as coisas de forma diferente - para testar e verificar os planos de execução para confirmar explicar /. É possível que as mudanças de comportamento entre as versões ...

Outras dicas

Definitivamente # 1. Ele "olha" assustadores, mas perceber o otimizador vai fazer a coisa certa e é expressivo de intenções. Também o é um pequeno bônus erro de digitação deve-se acidentalmente acho que existe, mas digite IN. # 2 é aceitável, mas não expressiva. A terceira opção fede na minha não tão humilde opinião. É muito perto de dizer "se 'nenhum valor' existe" para o conforto.

Em geral, é importante não ter medo de escrever código que mearly parece ineficiente se ele fornece outros benefícios e na verdade não afetar o desempenho.

Isto é, o otimizador irá quase sempre executar o seu complicado juntar / select / agrupamento magia para salvar uma simples EXISTE / subconsulta da mesma forma.

Depois de ter dado a si mesmo elogios para reescrever inteligentemente que desagradável ou fora de uma junção você acabará Realize o otimizador ainda usado o mesmo plano de execução de baixa qualidade para resolver o muito mais fácil entender consulta com incorporado ou de qualquer maneira.

A moral da história é saber o seu plataformas otimizador. Tente coisas diferentes e ver o que realmente está sendo feito porque os empurrões joelho galopante suposições a respeito 'decorativo' consulta otimização são quase sempre incorreta e irrelevante da minha experiência.

Sei que este é um post antigo, mas eu pensei que importante acrescentar clareza sobre por pode-se escolher um formato em detrimento de outro.

Em primeiro lugar, como já foi salientado, o motor de banco de dados é deveria para ignorar o Select cláusula. Cada versão do SQL Server tem / faz, a Oracle faz, MySQL faz e assim por diante. Em muitas, muitas luas de desenvolvimento de banco de dados, eu só já encontrei um DBMS que não ignoram corretamente o Select cláusula: Microsoft Access. Especificamente, as versões mais antigas do MS Access (Eu não posso falar para as versões atuais).

Antes da minha descoberta deste "recurso", eu costumava usar Exists( Select *.... No entanto, descobri que MS Access iria transmitir através de cada coluna na subconsulta e depois descartá-las (Select 1/0 também não iria funcionar). Isso convenceu-me mudar para Select 1. Se até mesmo um DBMS foi estúpido, outra poderia existir.

Escrevendo Exists( Select 1... é tão claro na transmissão de intenção (É francamente bobo com a reivindicação "É muito perto de dizer 'se 'nenhum valor' existe' para o conforto.") E faz com que as chances de um SGBD fazer algo estúpido com a Select quase impossível. Select Null iria servir o mesmo propósito, mas é simplesmente mais caracteres para escrever.

Mudei para Exists( Select 1 ter certeza absoluta de que o DBMS não poderia ser estúpido. No entanto, isso foi há muitas luas, e hoje eu esperaria que a maioria dos desenvolvedores esperaria ver Exists( Select * que irá funcionar exatamente o mesmo.

Dito isso, eu posso fornecer uma razão boa para evitar Exists(Select * mesmo se seu DBMS avalia-lo corretamente. É muito mais fácil de encontrar e trucidar todos os usos de Select * se você não tem que pular todas as instâncias de seu uso em uma cláusula EXISTS.

No SQL Server, pelo menos,

A menor quantidade de dados que podem ser lidos a partir do disco é uma "página" single de espaço em disco. Assim que o processador lê um registro que satisfaça os predicados subconsulta pode parar. A subconsulta não é executado como se ele estava de pé sobre o seu próprio, e depois incluído na consulta externa, ele é executado como parte do plano de consulta completo para a coisa toda. Então, quando usado como uma subconsulta, ele realmente não importa o que está na cláusula Select, nada é devolvido" à consulta externa de qualquer maneira, exceto um booleano para indicar se um único registro foi encontrado ou não ...

Todos os três uso exatamente o mesmo plano de execução

Eu uso sempre [Select * From ...] como eu acho que ele lê melhor, por não implicando que eu quero algo em particular retornado da subconsulta.

EDIT: De dave comentário costa ... Oracle também usa o mesmo plano de execução para todas as três opções

Esta é uma daquelas perguntas que beira iniciar algum tipo de guerra santa.

Há uma boa discussão sobre isso aqui .

Eu acho que a resposta é provavelmente a usar a terceira opção, mas o aumento de velocidade é tão infinitesimal que não é realmente vale a pena se preocupar. É facilmente o tipo de consulta que o SQL Server pode otimizar internamente mesmo, então você pode achar que todas as opções são equivalentes.

O EXISTS retorna um boolean não dados reais, que diziam melhor prática é usar # 3.

Execução do Plano . Aprendê-lo, usá-lo, amá-lo

Não há nenhuma maneira possível adivinhar, realmente.

Além do que já foi dito, a prática de usar SELECT 1 originou na antiga Microsoft SQL Server (antes 2005) - seu otimizador de consulta não foi suficiente inteligente para evitar fisicamente ir buscar campos da tabela para SELECT *. Nenhum outro DBMS, ao meu conhecimento, tem essa deficiência.

O EXISTE testes para a existência de linhas, não o que está neles, de modo que não seja algum otimizador peculiaridade semelhante ao anterior, isso realmente não importa o que está na lista SELECT.

O SELECT * parece ser mais comum, mas outros também são aceitáveis.

# 3 deve ser o melhor, como você não precisa os dados retornados de qualquer maneira. Trazendo os campos só irá adicionar uma sobrecarga extra

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