quinta-feira, 4 de fevereiro de 2010

SELECT NOT EXISTS !

Olá pessoal,

talvez vocês já tenham visto isso em algumas SPs e Views em que aparece o recurso "coluna1 + coluna2 + coluna3 + ... + colunaN" selecionando-as como uma chave, combinando
com outra tabela e fazendo operações de conjuntos, por exemplo:


SELECT * FROM
#TESTE1 as A
WHERE
A.CAMPO1 + A.CAMPO2 -- <-- "chave" da tabela A
NOT IN
(SELECT B.CAMPO1 + B.CAMPO2 -- <-- "chave" da tabela B
FROM #TESTE2 as B)

Significa que quero todos os elementos da tabela A, com exceção dos que
são igual aos da tabela B ligados pela "chave" CAMPO1 + CAMPO2 iguais ou seja, é
equivalente à operação algebrica:
conjunto (A) - (B)

Esse artifício é comum e funciona, mas tem um problema sério de performance
pois o SQL terá que concatenar as colunas da primeira table, depois da segunda,
para só depois verificar se existe ou não. Quanto maiores forem as tabelas,
geometricos são os tempos de demora.

Bem, existe uma maneira melhor de fazer subtração de conjuntos no SQL onde
eu não preciso combinar as colunas para fazer um elemento que responda como
uma chave, veja os exemplos a seguir, execute-os em um banco e acompanhe os
resultados:

A vantagem é que o SQL encherga as colunas das duas tabelas e, com isso, pode fazer uma pesquisa muito mais rápida.

Exemplo mostrando a equivalencia


DROP TABLE #TESTE1
DROP TABLE #TESTE2


CREATE TABLE #TESTE1
(TIPO CHAR(10),ALIMENTO CHAR(10),VAL1 INT,VAL2 INT)


CREATE TABLE #TESTE2
(TIPO CHAR(10),ALIMENTO CHAR(10),VAL1 INT,VAL2 INT)


SET NOCOUNT ON

INSERT INTO #TESTE1 VALUES('FRUTA','BANANA',1,1)
INSERT INTO #TESTE1 VALUES('FRUTA','ABACAXI',1,1)
INSERT INTO #TESTE1 VALUES('LEGUME','FEIJÃO',1,1)
INSERT INTO #TESTE1 VALUES('LEGUME','AMENDOIM',1,1)

INSERT INTO #TESTE2 VALUES('FRUTA','CEREJA',1,1)
INSERT INTO #TESTE2 VALUES('FRUTA','ABACAXI',1,1)
INSERT INTO #TESTE2 VALUES('LEGUME','FEIJÃO',1,1)
INSERT INTO #TESTE2 VALUES('LEGUME','AMENDOIM',1,1)

/* aqui, selecionamos todos os alimentos de mesmo tipo
que tenham no primeiro, menos os que já existam no segundo.
isso da a idéia de incremento entre as tabelas A e B.
*/


SELECT * FROM #TESTE1
WHERE TIPO + ALIMENTO
NOT IN
(SELECT TIPO + ALIMENTO FROM #TESTE2)

/* o resultado é o mesmo, mas nesse exemplo o SQL vê as chaves
e com isso pode combinar de uma maneira mais inteligente para.
obter equivalencias entre as tabelas. O banco seleciona a coluna
com menos elementos e faz a combinação delas, em seguida, combina
os dados da segunda coluna (ou a coluna com mais elementos, consecutivamente)
assim, ele consegue uma busca muito mais rápida.
*/


SELECT * FROM #TESTE1 AS A
WHERE
NOT EXISTS
(SELECT TIPO,ALIMENTO
FROM #TESTE2 AS B
WHERE
A.TIPO = B.TIPO
AND A.ALIMENTO = B.ALIMENTO)

Nenhum comentário :