Voici l'exemple de code:
CREATE TABLE #titles(
title_id varchar(20),
title varchar(80) NOT NULL,
type char(12) NOT NULL,
pub_id char(4) NULL,
price money NULL,
advance money NULL,
royalty int NULL,
ytd_sales int NULL,
notes varchar(200) NULL,
pubdate datetime NOT NULL
)
GO
insert #titles values ('1', 'Secrets', 'popular_comp', '1389', $20.00, $8000.00, 10, 4095,'Note 1','06/12/94')
insert #titles values ('2', 'The', 'business', '1389', $19.99, $5000.00, 10, 4095,'Note 2','06/12/91')
insert #titles values ('3', 'Emotional', 'psychology', '0736', $7.99, $4000.00, 10, 3336,'Note 3','06/12/91')
insert #titles values ('4', 'Prolonged', 'psychology', '0736', $19.99, $2000.00, 10, 4072,'Note 4','06/12/91')
insert #titles values ('5', 'With', 'business', '1389', $11.95, $5000.00, 10, 3876,'Note 5','06/09/91')
insert #titles values ('6', 'Valley', 'mod_cook', '0877', $19.99, $0.00, 12, 2032,'Note 6','06/09/91')
insert #titles values ('7', 'Any?', 'trad_cook', '0877', $14.99, $8000.00, 10, 4095,'Note 7','06/12/91')
insert #titles values ('8', 'Fifty', 'trad_cook', '0877', $11.95, $4000.00, 14, 1509,'Note 8','06/12/91')
GO
CREATE TABLE #sales(
stor_id char(4) NOT NULL,
ord_num varchar(20) NOT NULL,
ord_date datetime NOT NULL,
qty smallint NOT NULL,
payterms varchar(12) NOT NULL,
title_id varchar(80)
)
GO
insert #sales values('1', 'QA7442.3', '09/13/94', 75, 'ON Billing','1')
insert #sales values('2', 'D4482', '09/14/94', 10, 'Net 60', '1')
insert #sales values('3', 'N914008', '09/14/94', 20, 'Net 30', '2')
insert #sales values('4', 'N914014', '09/14/94', 25, 'Net 30', '3')
insert #sales values('5', '423LL922', '09/14/94', 15, 'ON Billing','3')
insert #sales values('6', '423LL930', '09/14/94', 10, 'ON Billing','2')
SELECT title, price
FROM #titles
WHERE EXISTS
(SELECT *
FROM #sales
WHERE #sales.title_id = #titles.title_id
AND qty >30)
SELECT t.title, t.price
FROM #titles t
inner join #sales s on t.title_id = s.title_id
where s.qty >30
Je veux savoir quelle est la différence entre les 2 requêtes ci-dessus qui donne le même résultat. Je veux également savoir à quoi sert le mot-clé EXISTS et où exactement l'utiliser?
EXISTS
est utilisé pour renvoyer une valeur booléenne, JOIN
renvoie une toute autre table
EXISTS
est uniquement utilisé pour tester si une sous-requête renvoie des résultats et court-circuite dès qu'elle le fait. JOIN
est utilisé pour étendre un jeu de résultats en le combinant avec des champs supplémentaires d'une autre table à laquelle il existe une relation.
Dans votre exemple, les requêtes sont symantiquement équivalentes.
En général, utilisez EXISTS
lorsque:
JOIN
peut provoquer des doublons de lignes si les valeurs sont répétées)LEFT OUTER JOIN...NULL
condition)Si vous disposez d'index appropriés, la plupart du temps, le EXISTS
fonctionnera de manière identique au JOIN
. L'exception concerne les sous-requêtes très compliquées, où il est normalement plus rapide d'utiliser EXISTS
.
Si votre clé JOIN
n'est pas indexée, il peut être plus rapide d'utiliser EXISTS
mais vous devrez tester votre situation spécifique.
La syntaxe JOIN
est plus facile à lire et plus claire normalement également.
Donc, avec 3 lignes et 5 lignes correspondant
Le résultat est l'effet de "court-circuit" mentionné par d'autres et pas besoin d'utiliser DISTINCT avec un JOIN. EXISTS est presque toujours plus rapide lorsque l'on recherche l'existence de lignes du côté n d'une relation 1: n.
EXISTS
est principalement utilisé pour les raccourcis. Essentiellement, l'optimiseur se renfloue dès que la condition est remplie, il n'est donc pas nécessaire d'analyser la table entière (dans les versions modernes de SQL Server, cette optimisation peut également se produire pour IN()
, bien que ce ne soit pas le cas toujours vrai). Ce comportement peut varier d'une requête à l'autre et, dans certains cas, la jointure peut en fait donner à l'optimiseur plus de possibilités pour effectuer son travail. Je pense donc qu'il est difficile de dire "c'est à ce moment-là que vous devriez utiliser EXISTS
, et c'est à ce moment-là que vous ne devriez pas" parce que, comme beaucoup de choses, "cela dépend".
Cela dit, dans ce cas, étant donné que vous avez essentiellement une correspondance 1: 1 entre les tables, il est peu probable que vous constatiez une différence de performances et l'optimiseur produira probablement un plan similaire, voire identique. Vous pouvez voir quelque chose de différent si vous comparez la jointure/existe sur la table des ventes lorsque vous ajoutez 50000 lignes pour chaque titre (peu importe que vous devrez modifier votre requête de jointure pour supprimer les doublons, l'agrégat, qu'avez-vous).
Je trouve que c'est plus utile lorsque j'ai des lignes que j'aimerais exclure en fonction de leur interaction avec les autres lignes.
Par exemple,
SELECT *
FROM TABLE a
WHERE a.val IN (1,2,3)
AND NOT EXISTS(SELECT NULL
FROM TABLE b
WHERE b.id = a.id
AND b.val NOT IN (1, 2, 3))
Dans ce cas, j'exclus une ligne dans ma requête a
basée sur un enregistrement b
avec le même identifiant mais non valide.
Cela venait en fait d'un problème de production que j'avais au travail . La requête a déplacé la majeure partie de la logique d'exclusion dans la requête plutôt que dans l'application, faisant passer le temps de chargement de plus de 24 secondes à moins de 2 secondes. :-)