Eu costumava escrever meus cheques EXISTS assim:
IF EXISTS (SELECT * FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Where Columns=@Filters
END
Um dos DBAs em uma vida anterior me disse que quando faço uma EXISTS
cláusula, uso em SELECT 1
vez deSELECT *
IF EXISTS (SELECT 1 FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Columns=@Filters
END
Isso realmente faz diferença?
sql
sql-server
tsql
Raj More
fonte
fonte
Respostas:
Não, o SQL Server é inteligente e sabe que está sendo usado para um EXISTS e não retorna NENHUM DADO ao sistema.
Quoth Microsoft: http://technet.microsoft.com/en-us/library/ms189259.aspx?ppud=4
Para verificar você mesmo, tente executar o seguinte:
Se ele estivesse realmente fazendo algo com a lista SELECT, ele lançaria um erro div por zero. Não é verdade.
EDIT: Nota, o SQL Standard realmente fala sobre isso.
ANSI SQL 1992 Standard, página 191 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
fonte
EXISTS
truque com 1/0 pode até mesmo ser estendido para issoSELECT 1 WHERE EXISTS(SELECT 1/0)
... parece um passo mais abstrato do que o segundoSELECT
não temFROM
cláusulaSELECT COUNT(*) WHERE EXISTS(SELECT 1/0)
. UmSELECT
sem umFROM
no SQL Server é tratado como se estivesse acessando uma tabela de linha única (por exemplo, semelhante à seleção dadual
tabela em outros RDBMSs)SELECT
cria uma tabela de 1 linha antes de fazer qualquer outra coisa, mesmo que1/0
a tabela de 1 linha ainda seja lixoEXISTS
?A razão para esse equívoco é provavelmente devido à crença de que ele acabará lendo todas as colunas. É fácil perceber que não é esse o caso.
Dá plano
Isso mostra que o SQL Server foi capaz de usar o índice mais estreito disponível para verificar o resultado, apesar de o índice não incluir todas as colunas. O acesso ao índice está sob um operador semi join, o que significa que ele pode interromper a varredura assim que a primeira linha for retornada.
Portanto, está claro que a crença acima está errada.
No entanto, Conor Cunningham, da equipe do Query Optimizer, explica aqui que ele normalmente usa
SELECT 1
neste caso, pois pode fazer uma pequena diferença de desempenho na compilação da consulta.Testei quatro maneiras possíveis de expressar essa consulta em uma tabela vazia com vários números de colunas.
SELECT 1
vsSELECT *
vsSELECT Primary_Key
vsSELECT Other_Not_Null_Column
.Executei as consultas em um loop usando
OPTION (RECOMPILE)
e medindo o número médio de execuções por segundo. Resultados abaixoComo pode ser visto, não há um vencedor consistente entre
SELECT 1
eSELECT *
e a diferença entre as duas abordagens é insignificante. OSELECT Not Null col
eSELECT PK
parece um pouco mais rápido.Todas as quatro consultas diminuem de desempenho conforme o número de colunas na tabela aumenta.
Como a tabela está vazia, essa relação parece explicável apenas pela quantidade de metadados da coluna. Pois
COUNT(1)
é fácil ver que isso foi reescritoCOUNT(*)
em algum ponto do processo a partir de baixo.O que dá o seguinte plano
Anexar um depurador ao processo do SQL Server e interromper aleatoriamente durante a execução do seguinte
Descobri que nos casos em que a tabela tem 1.024 colunas na maioria das vezes, a pilha de chamadas se parece com algo como o abaixo, indicando que está realmente gastando uma grande proporção do tempo carregando metadados de coluna, mesmo quando
SELECT 1
é usado (para o caso em que o a tabela tem 1 coluna que quebra aleatoriamente não atingiu esta parte da pilha de chamadas em 10 tentativas)Esta tentativa manual de criação de perfil é apoiada pelo criador de perfil de código do VS 2012, que mostra uma seleção muito diferente de funções consumindo o tempo de compilação para os dois casos ( 15 principais funções 1024 colunas vs 15 principais funções 1 coluna ).
As versões
SELECT 1
eSELECT *
terminam verificando as permissões da coluna e falham se o usuário não tiver acesso a todas as colunas da tabela.Um exemplo que tirei de uma conversa na pilha
Portanto, pode-se especular que a menor diferença aparente ao usar
SELECT some_not_null_col
é que ele apenas verifica as permissões naquela coluna específica (embora ainda carregue os metadados para todos). No entanto, isso não parece se adequar aos fatos, já que a diferença percentual entre as duas abordagens, se alguma coisa fica menor, conforme o número de colunas na tabela subjacente aumenta.Em qualquer caso, não irei me apressar e alterar todas as minhas consultas para este formulário, pois a diferença é muito pequena e apenas aparente durante a compilação da consulta. A remoção do
OPTION (RECOMPILE)
para que as execuções subsequentes possam usar um plano em cache forneceu o seguinte.O script de teste que usei pode ser encontrado aqui
fonte
A melhor maneira de saber é testar o desempenho de ambas as versões e verificar o plano de execução para ambas as versões. Escolha uma tabela com muitas colunas.
fonte
Não há diferença no SQL Server e nunca foi um problema no SQL Server. O otimizador sabe que eles são iguais. Se você olhar os planos de execução, verá que são idênticos.
fonte
Pessoalmente, acho muito difícil acreditar que eles não otimizem para o mesmo plano de consulta. Mas a única maneira de saber em sua situação particular é testando. Se você fizer isso, por favor, relate!
fonte
Nenhuma diferença real, mas pode haver um impacto muito pequeno no desempenho. Como regra geral, você não deve pedir mais dados do que precisa.
fonte