SELECT * FROM titles WHERE title_id NOT IN ( SELECT title_id FROM sales ) |--Nested Loops(Left Anti Semi Join, OUTER REFERENCES:([titles].[title_id])) |--Clustered Index Scan(OBJECT:([pubs].[dbo].[titles].[UPKCL_titleidind])) |--Index Seek(OBJECT:([pubs].[dbo].[sales].[titleidind]), SEEK:([sales].[title_id]=[titles].[title_id]) ORDERED FORWARD)And the second:
SELECT * FROM titles WHERE NOT EXISTS ( SELECT * FROM sales WHERE sales.title_id = titles.title_id) |--Nested Loops(Left Anti Semi Join, OUTER REFERENCES:([titles].[title_id])) |--Clustered Index Scan(OBJECT:([pubs].[dbo].[titles].[UPKCL_titleidind])) |--Index Seek(OBJECT:([pubs].[dbo].[sales].[titleidind]), SEEK:([sales].[title_id]=[titles].[title_id]) ORDERED FORWARD)So what we're seeing is that the SQL Sever optimizer has decided to solve both queries the same way. Normally, you would be right. The subquery should be faster than the corrolated-subquery. But here we're seeing how smart the query opimizer is.