Neste Post irei explicar um pouco sobre NOT IN x NOT EXISTS.
É mais comum o uso do NOT IN quando você quer ver os itens não existentes em outra tabela. Vamos ver as diferenças entre os comandos.
Vamos criar algumas tabelas para teste, criar Ăndices e inserir alguns registros.
CREATE TABLE Funcionario (FuncID int identity, Nome varchar(50))
ALTER TABLE Funcionario ADD CONSTRAINT PK_Funcionario PRIMARY KEY CLUSTERED(FuncID)
CREATE TABLE Setor (SetorID int identity, Descricao varchar(50), Gerente int not null)
ALTER TABLE Setor ADD CONSTRAINT PK_Setor PRIMARY KEY CLUSTERED(SetorID)
ALTER TABLE Setor ADD CONSTRAINT FK_Setor_Funcionario FOREIGN KEY(Gerente) REFERENCES Funcionario(FuncID)
CREATE NONCLUSTERED INDEX IX_Setor_Gerente ON Setor(Gerente)
GO
insert into Funcionario(Nome) values(NEWID())
GO 5000
insert into Setor(Descricao, Gerente) values('Financeiro',7)
insert into Setor(Descricao, Gerente) values('Contabil',6)
insert into Setor(Descricao, Gerente) values('Marketing',5)
insert into Setor(Descricao, Gerente) values('Patrimonio',2)
insert into Setor(Descricao, Gerente) values('Auditoria',3)
insert into Setor(Descricao, Gerente) values('Juridico',4)
insert into Setor(Descricao, Gerente) values('Pessoal',1)
Vamos executar agora 2 comandos e comparar os resultados.
Select FuncID from Funcionario where FuncID not in (select Gerente from Setor)
select FuncID from Funcionario where not exists (select Gerente from Setor where Setor.Gerente=Funcionario.FuncID)
NOT IN: costs=0,059 - logical reads(Setor)=2
NOT EXISTS: costs=0,059 - logical reads(Setor)=2
Veja que neste cenário os resultados são idênticos.
Vamos alterar a coluna referenciada, mudando ela pra NULL, sem alterar os valores.
ALTER TABLE Setor ALTER COLUMN Gerente int null
Executando os mesmos comandos, temos agora resultados diferentes.
select FuncID from Funcionario where FuncID not in (select Gerente from Setor)
select FuncID from Funcionario where not exists (select Gerente from Setor where Setor.Gerente=Funcionario.FuncID)
NOT IN: costs=0,571 - logical reads(Setor)=10001
NOT EXISTS: costs=0,059 - logical reads(Setor)=2
Veja que quando se utiliza NOT IN em colunas que permite nulo (mesmo nĂŁo tendo nenhum valor nulo) ele nĂŁo utiliza Ăndice.
Resultado: o NOT IN ficou 10 vezes mais lento e ao invés de acessar 2 páginas passou a acessar 10001 páginas.
Com este exemplo podemos perceber que o comando NOT EXISTS sempre será melhor.
Se ainda não se convenceu, no próximo post irei mostrar outros cenários e aprofundar um pouco mais e a partir daà nunca mais usará NOT IN.
Este exemplo também serviu para mostrar que devemos analisar melhor as tabelas ao criar o modelo, pois se você tem um campo que nunca receberá valor nulo, marque ele como NOT NULL.