My last question got me thinking.
1)
SELECT COUNT(*) INTO count FROM foo WHERE bar = 123;
IF count > 0 THEN
SELECT a INTO var FROM foo WHERE bar = 123;
-- do stuff
ELSE
-- do other stuff
END IF;
2)
BEGIN
SELECT a INTO var FROM foo where bar = 123;
-- do stuff
EXCEPTION
WHEN no_data_found THEN
--do other stuff
END ;
I assume number 2 is faster because it requires one less trip to the database.
Is there any situation where 1 would be superior, that I am not considering?
EDIT: I'm going to let this question hang for a few more days, to gather some more votes on the answers, before answering it.
Such a situation I usually do like this:
This has some benfits:
You read only one record from database, the rest you skip. Should be the fastest way of doing it in case you just have to know if number of rows > 1.
You don't handle a "normal" situation with an "exception" handler, some people consider this as "more beautiful" coding.
First see: Oracle PL/SQL - Are NO_DATA_FOUND Exceptions bad for stored procedure performance? that is essentially the same question than yours. And after that see About the performance of exception handling.
In both scenarios you should be prepared also to handle
too_many_rows
exception unless your database schema enforces uniqueness ofbar
.This is PL/SQL so you're on a constant database trip - instead you should be afraid/aware of PL/SQL - SQL context switches. See also what Tom says:
In first place you shouldn't be worried about the performance but the correctness of a program. In this regard my vote goes for scenario #2.
I'm not sure about faster, but I'd say (2) is clearly superior because you're not considering the case where someone issues
DELETE FROM foo where bar='123'
in between your statements in (1).If you use exact queries from the question then 1st variant of course slower because it must count all records in table which satisfies criteria.
It must be writed as
or
because checking for record existence is enough for your purpose.
Of course, both variants don't guarantee that someone else don't change something in
foo
between two statements, but it's not an issue if this check is a part of more complex scenario. Just think about situation when someone changed value offoo.a
after selecting it's value intovar
while performing some actions which refers selectedvar
value. So in complex scenarios better to handle such concurrency issues on application logic level.To perform atomic operations is better to use single SQL statement.
Any of variants above requires 2 context switches between SQL and PL/SQL and 2 queries so performs slower then any variant described below in cases when row found in a table.
There are another variants to check existence of row without exception:
If row_count = 1 then only one row satisfies criteria.
Sometime it's enough to check only for existence because of unique constraint on the
foo
which guarantees that there are no duplicatedbar
values infoo
. E.g.bar
is primary key.In such cases it's possible to simplify query:
or use cursor for processing values:
Next variant is from link, provided by @user272735 in his answer:
From my experience any variant without exception blocks in most cases faster then a variant with exceptions, but if number of executions of such block is low then better to use exception block with handling of
no_data_found
andtoo_many_rows
exceptions to improve code readability.Right point to choose to use exception or don't use it, is to ask a question "Is this situation are normal for application?". If row not found and it's a expected situation which can be handled (e.g. add new row or take data from another place and so on) is better to avoid exception. If it's unexpected and there are no way to fix a situation, then catch exception to customize error message, write it to event log and re-throw, or just don't catch it at all.
To compare performance just make a simple test case on you system whith both variants called many times and compare.
Say more, in 90 percent of applications this question is more theoretical than practical because there are a lot of another sources of performance issues which must be taken into account first.
Update
I reproduced example from this page at SQLFiddle site with a little corrections (link).
Results prove that variant with selecting from
dual
performs best: a little overhead when most of queries succeed and lowest performance degradation when number of missing rows raises.Surprisingly variant with count() and two queries showed best result in case if all queries failed.
Below is a setup code for test environment and test script.
-- f1 - exception handling
-- f2 - cursor loop
-- f3 - max()
-- f4 - select as field in select from dual
-- f5 - check count() then get value
Test script: