views:

295

answers:

3

So I have this SQL query,

<named-query name="NQ::job_exists">
<query>
select 0 from dual where exists (select * from job_queue);
</query>
</named-query>

Which I plan to use like this:

Query q = em.createNamedQuery("NQ::job_exists");
        List<Integer> results = q.getResultList();
        boolean exists = !results.isEmpty();
        return exists;

I am not very strong in SQL/JPA however, and was wondering whether there is a better way of doing it (or ways to improve it). Should I for example, write (select jq.id from job_queue jq) instead of using a star??

EDIT:This call is very performance critical in our app.

EDIT:Did some performance testing, and while the differences were almost negligible, I finally decided to go with:

select distinct null
    from dual 
       where exists (
               select null from job_queue
       );
+1  A: 

Why not just do:

select count(*) as JobCount from job_queue

If JobCount = 0, then there's your answer!

RedFilter
This call is very performance critical, and I wanted to exploit the performance benefit of EXSISTS..
Enno Shioji
That's important information worth adding to the OP.
RedFilter
I agree! Sorry about that.
Enno Shioji
+3  A: 

If you do an "exists" then it will stop looking as soon as it finds a match. This can stop it from doing a full table scan. Same with TOP 1 if you don't have an ORDER BY. If you do a TOP 1 ID and ID is in an index it might use the index and not even go to the table at all. Stopping the full table scan is where the biggest saving in performance is.

Another small savings is that if you do "SELECT 1" or "SELECT COUNT(1)" instead of "SELECT * " or "SELECT COUNT(*)" it saves the work of getting the table structure.

So I would go with:

SELECT TOP 1 1 AS Found
FROM job_queue

Then:
return !results.isEmpty();

This is the least amount of work that I can think of.

For Oracle it would be:

SELECT 1 
FROM job_queue
WHERE rownum<2;

Or:

Set Rowcount 1
SELECT 1 
FROM job_queue
JBrooks
Hmm.. This sounds very clean. Thank you!
Enno Shioji
It would be even better (though SQL Server specific) if you use "SELECT TOP 1 1 AS Found FROM job_queue WITH (FASTFIRSTROW)" - the hind will tell SQL Server to optimize plan for returning first matching row as soon as possible.
AlexS
TOP is not valid syntax in Oracle.
APC
In this context Oracle will treat select 1 or select * identically. Select count(1) or count(*) would be slower as it is an aggregate function and will deals with all rows
Gary
@APC Added Oracle specific code.
JBrooks
+1 to Gary. It is entirely incorrect to suggest that "SELECT COUNT(1)" is any better than "SELECT COUNT(*)" in Oracle.
Jeffrey Kemp
Sorry I had to strip the accepted mark (see my edit on the question). Thanks for the good suggestion anyways!
Enno Shioji
+5  A: 

IF you are using EXISTS Oracle I recommend using null:

select null 
  from dual where exists (select null from job_queue);

The following will be the one with lower cost on Oracle:

select null
  from job_queue
 where rownum = 1;

Update: To include the case when there are no rows on table you can run the following query:

select count(*)
  from (select null
          from job_queue
          where rownum = 1);

With this query you have a optimum plan and only two possible results: 1 if there are rows and 0 if there are no rows.

FerranB
+1 for `where rownum = 1` which is the most expressive solution using vernacular Oracle syntax.
APC
Concur. Just make sure that there's at least one column in the table that's mandatory (not null) and indexed.
Adam Musch
In an EXISTS subquery it doesn't matter whether you select *, NULL or some literal value. I prefer NULL myself, but some people like to save their fingers by typing 3 fewer characters :)
Jeffrey Kemp