Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Deux sélections ou une sélection + une jointure en SQL ?

Votre idée qu'ils devraient faire le même travail n'est pas vraie. Imaginez cet ensemble de données de test :

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;

Résultats

ID
---
1
2
3

ID
---
1
1
1
2
2
3

Vos résultats ne sont identiques que si la colonne dans laquelle vous effectuez la recherche est unique.

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;

Même si les résultats sont les mêmes, le plan d'exécution ne l'est pas. La première requête utilisant IN est capable d'utiliser une jointure anti-semi, ce qui signifie qu'il sait que les données de t2 ne sont pas nécessaires, donc dès qu'il trouve une seule correspondance, il peut arrêter de rechercher d'autres correspondances.

Si vous contraignez votre deuxième table à n'avoir que des valeurs uniques, vous verrez le même plan :

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;

En résumé, les deux requêtes ne donneront pas toujours les mêmes résultats, et elles n'auront pas toujours le même plan. Cela dépend vraiment de vos index et de la largeur de vos données/requêtes.