views:

1242

answers:

3

The RIGHT JOIN on this query causes a TABLE ACCESS FULL on lims.operator. A regular join runs quickly, but of course, the samples 'WHERE authorised_by IS NULL' do not show up.

Is there a more efficient alternative to a RIGHT JOIN in this case?

  SELECT   full_name
  FROM       (SELECT   operator_id AS authorised_by, full_name
                FROM lims.operator)
  RIGHT JOIN (SELECT   sample_id, authorised_by
                FROM   lims.sample
               WHERE   sample_template_id = 200)
  USING (authorised_by)

NOTE: All columns shown (except full_name) are indexed and the primary key of some table.

+1  A: 

No need to nest queries. Try this:

select s.full_name
from lims.operator o, lims.sample s
where o.operator_id = s.authorised_by(+)
and s.sample_template_id = 200
BQ
This query still causes a 'TABLE ACCESS FULL' on lims.operator.
Steven
I would never ever use this (+) joins again since there are real ansi joins for oracle (since version 9 I think). The (+) operator does not always work (eg. you cannot left outer join from A to B and left outer join from B to C), but oracle doesn't tell this and silently returns wrong results. It's awkward and unpredictable. I don't like it.
Stefan Steinegger
Then you aren't indexed by operator_id on the lims.operator table.
BQ
Think so too. You should check your index
Stefan Steinegger
@Stefan: Point noted (it's a habit I've used since Oracle 8i at least), but works fine if you're aware of its limitations. Much of the code I work with (and maintain) is written like this, so it's more familiar to me.
BQ
Or statistics are stale...
DCookie
The column operator_id is the primary key of lims.operator. I can post the script to recreate the table if you would like.
Steven
+1  A: 

I didn't write sql for oracle since a while, but i would write the query like this:

SELECT lims.operator.full_name
FROM       lims.operator
RIGHT JOIN lims.sample
           on lims.operator.operator_id = lims.sample.authorized_by
           and sample_template_id = 200

Does this still perform that bad?

Stefan Steinegger
This query causes a 'TABLE ACCESS FULL' on lims.operator.
Steven
+1: Essentially the same as mine, but with the "RIGHT JOIN" syntax instead of Oracle's (+) syntax. Probably easier to read if you alias the tables too.
BQ
@Steven, did you check the index on lims.operator.authorized_by? It must be an index ONLY on this field.
Stefan Steinegger
It's actually the operator_id column on the operator table he's using (you may want to edit your answer to reflect this), but Oracle can use a composite index if needed (and if the query plan show's it's the best option).
BQ
thanks, fixed it. @Steven again: did you check the index on lims.operator.operator_id ? It must be the primary key. I can hardly believe that it performs a full table scan on this.
Stefan Steinegger
+1  A: 

Since you're doing an outer join, it could easily be that it actually is more efficient to do a full table scan rather than use the index.

If you are convinced the index should be used, force it with a hint:

SELECT /*+ INDEX (lims.operator operator_index_name)*/ ...

then see what happens...

DCookie
I believe that to be the case as lims.operator only has 82 entries. I inserted the INDEX hint which removed the index, however the trace comparison was nearly identical.
Steven
82 rows could amount to a single block. Oracle *does* get it right, usually :-)
DCookie