I have a query that I would like to save as a view:
WITH subquery AS ( SELECT aaa_id, ... FROM table_aaa ... )
SELECT subquery.aaa_id, ... FROM table_bbb JOIN subquery USING ( ... )
;
[NOTE: In real-life, my query is much more complicated than this, with several WITH sub-queries, many performing JOINS, all being JOINed together. But I’m looking for general guidance that I can use to work into my problem.]
The execution for this query include full table scans. This makes sense since there are no criteria included in a WHERE clause. However, I can eliminate most of the full table scans by including such a clause:
WITH subquery AS ( SELECT aaa_id, ... FROM table_aaa ... WHERE aaa_id = :id)
SELECT subquery.aaa_id, ... FROM table_bbb JOIN subquery USING ( ... )
;
However, it doesn’t seem that I have the option of putting the WHERE condition in the right place when I create the view:
CREATE OR REPLACE VIEW vw_my_view AS
WITH subquery AS ( SELECT aaa_id, ... FROM table_aaa ... )
SELECT subquery.aaa_id, ... FROM table_bbb JOIN subquery USING ( ... )
;
SELECT ... FROM vw_my_view WHERE aaa_id = :id
;
In this case, the execute plan still contains the full table scans. Is there a way for me to hint that the WHERE clause can actually be inserted into the WITH sub-query?
I’ve had similar experiences and while I have no general solution, I would suggest the following:
run “SELECT * FROM v$parameter2;” and make sure that _complex_view_merging is on. There was a nasty bug in one of the early 10g releases that was related to it so some dbas turned it off and might have forgotten to turn it back on once it was fixed.
Leave all consideration about hints as a last measure. In my experience, they’re rarely useful for preventing full table scans because the optimizer is already doing everything it can to avoid them.
If you have a base table whose primary key is what you’re ultimately going to be filtering the view on, try to set things up so that your view’s main query starts with that and then joins to your complicated with clause queries, even if that join is completely redundant (i.e. give oracle a chance to do easy filtering on that base table before joining to the complicated bits). Make sure that the columns that the view is going to be filtered on are selected directly from that base table and not the complicated_query. So something like
.
If you have filters that use an uncorrelated subquery, try switching them to a correlated equivalent (and vice versa).
Play around with the order of your join statements and/or which table you start out with in your FROM clause, even if logically it will not make a difference to the outcome. This is a bit of a desperate gambit, but I’ve definitely had execution plans change for the better by doing this. Optimizing Oracle queries is not always a rational process.