37

I have two tables Institutions and Results and I want to see if there are any results for institutions that way I can exclude the ones that don't have results.

Can I get better performance using a JOIN or using EXISTS?

Thank you,
-Nimesh

Chris Marasti-Georg
  • 34,091
  • 15
  • 92
  • 137
  • It's not a real question because it's extremely generic. He needs to at least specify at least a little more context. – Onorio Catenacci Oct 22 '08 at 18:45
  • I added the subjective tag because of the extremely generic nature of the question. – Onorio Catenacci Oct 22 '08 at 18:45
  • @NImesh--in this particular case, details are your friend. The more details you can provide the more likely you are to get a useful, constructive answer. Which flavor of SQL (i. e. Oracle or MS SQL Server)? What's the structure of the tables you're querying? Etc. etc. etc. – Onorio Catenacci Oct 22 '08 at 18:47
  • I hope my edit is reasonable. Feel free to roll it back if that's not in the spirit of your original question. – Mark Biek Oct 22 '08 at 18:47
  • You should show the full SQL query using each method so we can get a better idea of what you're trying to do. – Bill the Lizard Oct 22 '08 at 18:48

12 Answers12

25

Depending on the statement, statistics and DB server it may make no difference - the same optimised query plan may be produced.

There are basically 3 ways that DBs join tables under the hood:

  • Nested loop - for one table much bigger than the second. Every row in the smaller table is checked for every row in the larger.

  • Merge - for two tables in the same sort order. Both are run through in order and matched up where they correspond.

  • Hash - everything else. Temporary tables are used to build up the matches.

By using exists you may effectively force the query plan to do a nested loop. This may be the quickest way, but really you want the query planner to decide.

I would say that you need to write both SQL statements and compare the query plans. You may find that they change quite a bit depending on what data you have.

For instance if [Institutions] and [Results] are similar sizes and both are clustered on InstitutionID a merge join would be quickest. If [Results] is much bigger than [Institutions] a nested loop may be quicker.

Keith
  • 150,284
  • 78
  • 298
  • 434
17

It depends.

Ultimately the 2 serve entirely different purposes.

You JOIN 2 tables to access related records. If you don't need to access the data in the related records then you have no need to join them.

EXISTS can be used to determine if a token exists in a given dataset but won't allow you to access the related records.

Post an example of the 2 methods you have in mind and I might be able to give you a better idea.


With your two tables Institutions and Results if you want a list of institutions that have results, this query will be most efficient:

select Institutions.institution_name 
from Institutions
inner join Results on (Institutions.institution_id = Results.institution_id)

If you have an institution_id and just want to know if it has results, using EXISTS might be faster:

if exists(select 1 from Results where institution_id = 2)
  print "institution_id 2 has results"
else
  print "institution_id 2 does not have results"
VVS
  • 19,405
  • 5
  • 46
  • 65
Bob Probst
  • 9,533
  • 8
  • 32
  • 41
  • 1
    Since your explanations are fine, "might be faster" is a little short answer to the question which one of the options is faster. – Magier Dec 02 '16 at 09:45
6

I'd say a JOIN is slower, because your query execution stops as soon as an EXISTS call finds something, while a JOIN will continue until the very end.

EDIT: But it depends on the query. This is something that should be judged on a case-by-case basis.

Kon
  • 27,113
  • 11
  • 60
  • 86
  • In his case he's looking for an absence of data so it will still need to scan the entire Results table (or, hopefully, index) – Bob Probst Oct 22 '08 at 19:14
  • True. I posted that before he clarified.. I might as well delete this answer.. not sure if I should. :) – Kon Oct 22 '08 at 19:39
  • 5
    Glad you didn't delete it - it provided a useful insight! (that EXISTS short-circuits...) – Oscar Bravo Jan 04 '21 at 14:28
6

Whether there's a performance difference or not, you need to use what's more appropriate for your purpose. Your purpose is to get a list of Institutions (not Results - you don't need that extra data). So select Institutions that have no Results... translation - use EXISTS.

Kon
  • 27,113
  • 11
  • 60
  • 86
6

It depends on your optimizer. I tried the below two in Oracle 10g and 11g. In 10g, the second one was slightly faster. In 11g, they were identical.

However, #1 is really a misuse of the EXISTS clause. Use joins to find matches.

select *
from
  table_one t1
where exists (
             select *
             from table_two t2
             where t2.id_field = t1.id_field
             )
order by t1.id_field desc


select t1.*
from 
  table_one t1
 ,table_two t2
where t1.id_field = t2.id_field
order by t1.id_field desc 
JosephStyons
  • 57,317
  • 63
  • 160
  • 234
  • 1
    maybe if in the 1st option the sub-query returns only t2.id_field instead of *, it could compensate the time. Sometimes the size of the return also affects performance. Specially in this case that is just slightly different. Good luck and thanks!!! – tanovellino Aug 16 '17 at 12:36
  • Style of the 2nd query has been deprecated. Don't do that. And don't use splats. But do use schema. – ARLibertarian Feb 09 '21 at 20:47
2

A LEFT OUTER JOIN will tend to perform better than a NOT EXISTS**, but in your case you want to do EXISTS and using a simple INNER JOIN doesn't exactly replicate the EXISTS behavior. If you have multiple Results for an Institution, doing the INNER JOIN will return multiple rows for that institution. You could get around that by using DISTINCT, but then the EXISTS will probably be better for performance anyway.

** For those not familiar with this method:

SELECT
     MyTable.MyTableID
FROM
     dbo.MyTable T1
LEFT OUTER JOIN dbo.MyOtherTable T2 ON
     T2.MyTableID = T1.MyTableID
WHERE
     T2.MyOtherTableID IS NULL

is equivalent to

SELECT
     MyTable.MyTableID
FROM
     dbo.MyTable T1
WHERE NOT EXISTS (SELECT * FROM MyOtherTable T2 WHERE T2.MyTableID = T1.MyTableID)

assuming that MyOtherTableID is a NOT NULL column. The first method generally performs faster than the NOT EXISTS method though.

Tom H
  • 46,766
  • 14
  • 87
  • 128
  • See http://dba.stackexchange.com/a/4010/630 + subsequent links. LEFT JOIN may require a DISTINCT which will bollix you too. *Generally* EXISTS is quicker and semantically correct – gbn Feb 24 '12 at 07:35
1

Are you using EXISTS as part of a correlated subquery? If so, the join will almost always be faster.

Your database should have ways of benchmarking queries. Use them to see which query runs faster.

Barry Brown
  • 20,233
  • 15
  • 69
  • 105
1

Actually, from your vague description of the problem, it sounds to me like a NOT IN query is the most obvious way to code it:

SELECT *
  FROM Institutions
  WHERE InstitutionID NOT IN (
     SELECT DISTINCT InstitutionID
       FROM Results
     )
Dave Costa
  • 47,262
  • 8
  • 56
  • 72
  • Why in the world would you add a distinct? Either the number 1 is in this list ( 1, 1, 1, 2, 2, 5, 5, 7) or it is not. It's completely unimportant to sort and filter the list. In fact, when i do it in 10.2.0.3, it's completely ignored. –  Oct 22 '08 at 20:47
  • In my experience looking at execution plans, Oracle will filter it down to unique values whether you have the DISTINCT keyword or not. Therefore I like to include it since it makes the purpose of the code clearer. – Dave Costa Oct 23 '08 at 12:46
1

If the RESULTS table has more than one row per INSTITUTION, EXISTS() has the added benefit of not requiring you to select distinct Institutions.

As for performance, I have seen joins, IN(), and EXISTS() each be fastest in a variety of uses. To find the best method for your purposes you must test.

Chandra Sekhar
  • 16,256
  • 10
  • 67
  • 90
Noah Yetter
  • 396
  • 2
  • 9
1

In cases like above the Exists statement works faster than that of Joins. Exists will give you a single record and will save the time also. In case of joins the number of records will be more and all the records must be used.

Pk9
  • 11
  • 1
  • 1
    Welcome to stackoverflow. This question is quite old and was well covered . Before resurrecting such an old thread, please be sure your response adds something significant to the conversation, – Leigh Apr 05 '12 at 16:23
0

If you're referring to using a left (or right) outer join or a not exists subquery, I'm fairly certain the left outer join wins performance-wise. For example:

SELECT t1.* FROM table1 t1 LEFT OUTER JOIN table2 t2 ON t1.id = t2.id WHERE t2.id IS NULL

The above should be quicker than the equivalent sub-query, and if you're referring specifically to exists - well, where structure allows, an inner join will always be the preferred option.

BrynJ
  • 8,322
  • 14
  • 65
  • 89
0

If you want the institutions that did not have results, then a 'Where Not Exists' subquery will be faster, as it will stop as soon as it finds a single result for those that have results...

If you want the institutions With results, but you don't actually want the results, same thing. Use a 'Where Exists' subquery.. It will stop as soon as it finds a single result... This also ensures that the result set will only have one record per institution, whereas if you had an institution with multiple results, using the join approach would require that you add the 'distinct' keyword or a 'Group By' clause to eliminate the duplicate cartesion product rows that would be prodcued from the multiple Result records that matched to a single insitution.

If you need the Results, then do a JOIN - An Inner Join if you don't want to see the insitutions without results, and an outer join if you want to see ALL institutions, including the ones with no Results.