Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Due selezioni o una selezione + un'unione in SQL?

La tua idea che dovrebbero fare lo stesso lavoro non è vera. Immagina questo set di dati di prova:

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;

Risultati

ID
---
1
2
3

ID
---
1
1
1
2
2
3

I risultati sono gli stessi solo se la colonna in cui stai cercando è unica.

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;

Anche se i risultati sono gli stessi, il piano di esecuzione non lo è. La prima query che utilizza IN è in grado di utilizzare un anti-semi join, il che significa che sa che i dati in t2 non sono necessari, quindi non appena trova una singola corrispondenza può interrompere la ricerca di ulteriori corrispondenze.

Se limiti la tua seconda tabella ad avere solo valori univoci, vedrai lo stesso piano:

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;

In sintesi, le due query non produrranno sempre gli stessi risultati e non avranno sempre lo stesso piano. Dipende davvero dai tuoi indici e dalla larghezza dei tuoi dati/query.