Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Duas seleções ou uma seleção + uma junção no SQL?


Sua noção de que eles deveriam fazer o mesmo trabalho não é verdadeira. Imagine este conjunto de dados de teste:

T1
ID
----
1
2
3
4
5

T2
ID
---
1
1
1
2
2
3

DDL
CREATE TABLE dbo.T1 (ID INT NOT NULL);
INSERT dbo.T1 (ID) VALUES (1), (2), (3), (4), (5);

CREATE TABLE dbo.T2 (ID INT NOT NULL);
INSERT dbo.T2 (ID) VALUES (1), (1), (1), (2), (2), (3);

SELECT  *
FROM    dbo.T1
WHERE   T1.ID IN (SELECT T2.ID FROM dbo.T2);

SELECT  T1.*
FROM    dbo.T1
        INNER JOIN dbo.T2
            ON T1.ID = T2.ID;

Resultados
ID
---
1
2
3

ID
---
1
1
1
2
2
3

Seus resultados são os mesmos apenas se a coluna na qual você está pesquisando for única.
CREATE TABLE dbo.T1 (ID INT NOT NULL);
INSERT dbo.T1 (ID) VALUES (1), (2), (3), (4), (5);

CREATE TABLE dbo.T2 (ID INT NOT NULL);
INSERT dbo.T2 (ID) VALUES (1), (2), (3);

SELECT  *
FROM    dbo.T1
WHERE   T1.ID IN (SELECT T2.ID FROM dbo.T2);

SELECT  T1.*
FROM    dbo.T1
        INNER JOIN dbo.T2
            ON T1.ID = T2.ID;



Embora os resultados sejam os mesmos, o plano de execução não é. A primeira consulta usando IN é capaz de usar uma junção anti-semi, o que significa que sabe que os dados em t2 não são necessários, portanto, assim que encontrar uma única correspondência, ele poderá parar de verificar outras correspondências.

Se você restringir sua segunda tabela a ter apenas valores exclusivos, verá o mesmo plano:
CREATE TABLE dbo.T1 (ID INT NOT NULL PRIMARY KEY);
INSERT dbo.T1 (ID) VALUES (1), (2), (3), (4), (5);

CREATE TABLE dbo.T2 (ID INT NOT NULL PRIMARY KEY);
INSERT dbo.T2 (ID) VALUES (1), (2), (3);

SELECT  *
FROM    dbo.T1
WHERE   T1.ID IN (SELECT T2.ID FROM dbo.T2);

SELECT  T1.*
FROM    dbo.T1
        INNER JOIN dbo.T2
            ON T1.ID = T2.ID;



Em resumo, as duas consultas nem sempre produzirão os mesmos resultados e nem sempre terão o mesmo plano. Realmente depende de seus índices e da largura de seus dados/consulta.