views:

53

answers:

2

Suppose I have the following query:

select * from A, B, C, D
where A.x = B.x
and B.y = C.y
and A.z = D.z

I have indexes on A.x and B.x and B.y and C.y and D.z

There is no index on A.z.

How can I give a hint to this query to use an INDEX hint on A.x but a USE_HASH hint on A.z? It seems like hints only take the table name, not the specific join, so when using a single table with multiple joins I can only specify a single strategy for all of them.

Alternative, suppose I'm using a LEADING or ORDERED hint on the above query. Both of these hints only take a table name as well, so how can I ensure that the A.x = B.x join takes place before the A.z = D.z one? I realize in this case I could list D first, but imagine D subsequently joins to E and that the D-E join is the last one I want in the entire query.

A third configuration -- Suppose I want the A.x join to be the first of the entire query, and I want the A.z join to be the last one. How can I use a hint to have a single join from A to take place, followed by the B-C join, and the A-D join last?

A: 

On SQL Server, you would do a hash joint hint like this

SELECT * FROM table1 t1
INNER hash join table2 t2 ON  t1.id = t2.id

and you can also supply an index hint

select * from table1 t1
inner  join table2 t2 with (index( bla))  on  t1.id = t2.id

Don't know what the syntax looks like in Oracle, BTW why are you using old style joins? Are you still on 8i?

SQLMenace
We're using 10g. I find the "old" style joins to be more readable than the newer syntax. I've made a couple forays into the ANSI join syntax but I didn't feel like I was gaining much. I was also a little unsure about how specifying non-join conditions in the ON clauses was handled, and I spent a lot more time jumping around from place to place than when all the joins are in one block.
RenderIn
As one who bit the bullet and switched to the ANSI join syntax in the not too distant past, at first I too didn't see the point. It seemed awkward. Now I'm a big fan. First, if you ever have to use a different DBMS (e.g., SQL Server) you'll not struggle with syntax. It's actually more intuitive, once you change your thinking. You don't have people asking you what the "+" sign means. It's more readable. Don't know what you mean by "all the joins in one block", you can certainly have multiple joins in one select. I'm happy I made the change, despite initial resistance.
DCookie
+3  A: 

First of all, using such hints should be the last resort, not a normal way of writing queries. Most of the time you should just ensure that optimiser stats are up to date and let the CBO work out the optimum path for itself - that's its job!

The INDEX hint can specify the name of the index you want to use like this:

SELECT /*+ INDEX (A, A_X_IDX) */ *
...

(assuming the index on A.X is called A_X_IDX).

You can't tell Oracle use use the index on A.X and use a hash join to table A in the same statement, that makes no sense. However, you can (if you must) specify the access path for each table something like:

SELECT /*+ INDEX (A, A_X_IDX) INDEX(B, B_Y_IDX) USE_HASH(C) */ *

But to reiterate, it should be rare to need to do this. Oracle have invested millions of dollars and manhours into developing the CBO, so why effectively switch it off?

Tony Andrews
I have been mostly pleased with the behavior of the default optimization, but for this particular query (spans a DB link and uses several views) it is showing an estimated cost of ~700 when I run an explain plan without any hints. When I run the query without hints it takes ~30 seconds to return. When I specify a LEADING hint it shows a cost of ~950 but returns in ~3.5 seconds. It's quite frustrating to have to get to this level of specificity, but I don't see any other options.
RenderIn
DB links can be a big performance hit. The DRIVING_SITE hint can be useful here - see http://download.oracle.com/docs/cd/B28359_01/server.111/b28310/ds_appdev004.htm
Tony Andrews