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.