Home>Question Details



Matthew -- Thanks for the question regarding "Force cursor to reparse", version 10.1

Submitted on 27-Dec-2007 14:14 Central time zone
Last updated 16-Jun-2008 13:52

You Asked

Dear Tom,

We have an outbound interface, the specifications of which are mostly out of our control, where there is an "incremental" mode that is run nightly and a "full" mode that is done weekly. The interface involves dozens of large queries that pull data from various sources in the Oracle e-Business 11i data model.

For the incremental mode, we want the queries to include a predicate like:

and last_update_date >= :l_last_run_date


And we want the full mode to omit all such predicates.

We would like to avoid using dynamic SQL (since we find that hard to read and hard to maintain since you don't catch syntax errors until runtime). We would also like to avoid having 2 sets of queries (one with the predicate and one without).

How would you do that?

One idea floating around here is that, for the full mode, we can pass :l_last_run_date a value far, far in the past, which will qualify all rows. What concerns me about that is that everything I know about bind variables tells me that it is either going to use the index on last_update_date every time (good for incremental, bad for full mode) or it is going to FTS every time ( good for full mode, bad for incremental), based on whatever the value is the first time it is run. I know 11g has adaptive cursors, but we're not there yet.

Is this even a viable approach? Are my concerns about bind variables in this case valid? And, if so, is there a way to force the cursor to reparse each time it is executed (again, without dynamic SQL)?

Thanks in advance for your consideration!

Best regards,
Matt

and we said...

I would change my mind - about having two sets of queries that is.

You have two needs, two requirements. Two different things. I have no problem with two different cursors. You want two plans in all likelihood - you want two cursors.

One approach if you are doing this procedurally is ref cursors:


if ( cond1 ) 
then
   open c for select .....;
else 
   open c for select .....;
end if;
loop
    fetch c bulk collect ....;







Reviews    
5 stars Suggestion: view   December 28, 2007 - 1pm Central time zone
Reviewer: Stew Ashton from Paris, France

In addition to Tom's answer, to alleviate your concerns about dynamic SQL and having two sets of queries, you could put the "full mode" query in a view. That would catch syntax errors, simplify your code and allow you to make future changes in one place.

5 stars use case   December 31, 2007 - 7am Central time zone
Reviewer: Karthick from India
and last_update_date >= :l_last_run_date

can be writern as

and last_update_date >= case MODE when 'FULL' then last_update_date else :l_last_run_date end


Followup   January 1, 2008 - 6pm Central time zone:

you missed the point.

they WANT two different plans - one that uses an index (when a date is supplied) and one that does not (when all of the data will be accessed)

if you use a single statement - you'll get a single plan... (that is what shared sql is all about)
4 stars Re-parse may not be needed   January 2, 2008 - 9am Central time zone
Reviewer: Mike from Cleveland, OH USA
We have had luck with a technique like this, where in_ACCT_NBR represents an 'optional' filter condition:
  1  explain plan for
  2  SELECT *
  3  FROM   ACCT_TB    
  4* WHERE  ACCT_NBR = nvl(:in_ACCT_NBR, ACCT_NBR)
09:27:49 > /

Explained.

Elapsed: 00:00:01.52
09:27:52 > SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------
Plan hash value: 3506087093

----------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |  1958K|  1701M|   178K  (2)| 00:35:43 |
|   1 |  CONCATENATION                |              |       |       |            |          |
|*  2 |   FILTER                      |              |       |       |            |          |
|*  3 |    TABLE ACCESS FULL          | ACCT_TB      |  1958K|  1701M|   178K  (2)| 00:35:43 |
|*  4 |   FILTER                      |              |       |       |            |          |
|   5 |    TABLE ACCESS BY INDEX ROWID| ACCT_TB      |     1 |   911 |     1   (0)| 00:00:01 |
|*  6 |     INDEX UNIQUE SCAN         | ACCT_IDX     |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter(:IN_ACCT_NBR IS NULL)
   3 - filter("ACCT_NBR" IS NOT NULL)
   4 - filter(:IN_ACCT_NBR IS NOT NULL)
   6 - access("ACCT_NBR"=:IN_ACCT_NBR)

Note
-----
   - 'PLAN_TABLE' is old version

25 rows selected.

Elapsed: 00:00:00.37

With this technique, either (step 3) or (steps 5+6) will be executed - not both.

One caveat: the column you are filtering on should be NOT NULL; otherwise NULL values will be excluded even if the input is null - by the predicate that resolves to (NULL = NULL).

Followup   January 2, 2008 - 11am Central time zone:

yes, that is called nvl or expansion
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:7555175291763


and works on simple queries however the above poster said:

... The interface involves dozens of large queries that pull data from various sources in the Oracle e-Business 11i data model. ...

so the odds of it coming into play are near.... zero%
3 stars To Mike from Cleveland, OH USA   January 2, 2008 - 10am Central time zone
Reviewer: A reader from London
"One caveat: the column you are filtering on should be NOT NULL; otherwise NULL values will be 
excluded even if the input is null - by the predicate that resolves to (NULL = NULL)."

NULL = NULL won't return any rows...  as NULL can only be checked with "IS NULL" or "IS NOT NULL" 
clause.

HDH



4 stars NULL=NULL - yes, that was my point   January 2, 2008 - 11am Central time zone
Reviewer: Mike from Cleveland, OH USA
The 'expected behavior' here is that a null input does not filter.

If you provide a null input (implying no filtering) but you have a null column value, that will 
have the undesirable result of being filtered out - because you will end up with a predicate that 
resolves to NULL=NULL which is always false.

If your columns is defined as NOT NULL then you can be confident you will not fall into this. If it 
may be null, then you have to be more careful and more verbose in the query. And your 
more-elaborate query may or may not be able to get the nice dual-purpose plan I showed here.


3 stars New idea for this   June 16, 2008 - 7am Central time zone
Reviewer: Matthew McPeak 
What about putting logic in like this:

SELECT <system-wide optimizer_index_cost_adj setting>
INTO  x;

IF FULL_MODE THEN
  execute immediate 'alter session set optimizer_index_cost_adj = ' || x; 
ELSE
  execute immediate 'alter session set optimizer_index_cost_adj = ' || x+1;
END IF;

Would this not force the optimizer to come up with two plans -- one for full mode and one for our 
incremental mode?  (Please don't bother to comment on the lack of bounds checking for when X=100.)

Thanks in advance for any comments!



Followup   June 16, 2008 - 12pm Central time zone:

If this is true:


For the incremental mode, we want the queries to include a predicate like:

and last_update_date >= :l_last_run_date



And we want the full mode to omit all such predicates.

We would like to avoid using dynamic SQL (since we find that hard to read and hard to maintain 
since you don't catch syntax errors until runtime). We would also like to avoid having 2 sets of 
queries (one with the predicate and one without). 


then this will be my answer:

if ( cond1 ) 
then
   open c for select .....;
else 
   open c for select .....;
end if;
loop
    fetch c bulk collect ....;



it is not dynamic sql, it omits the where clause when you want it omitted. It is straightforward, it relies on no tricks, it would be in my estimation the way to go
3 stars Thanks!   June 16, 2008 - 1pm Central time zone
Reviewer: Matthew McPeak 
Thank you.  I think I understand what you are saying about being straight-forward.  I've seen (and 
sadly committed) many examples of the fact that "clever" != "smart".

But the "open c for select ...." that gets nearly duplicated is actually 2,200 lines of cursor code 
and I have to think that a 5 line "trick" is going to wind up being more straight-forward and 
maintainable than 2,200 lines of near duplicate SQL.

Anyway, even though I was hoping to hear something more along the lines of "go for it", I really 
appreciate your assistance.  Thank you.




Followup   June 16, 2008 - 1pm Central time zone:

.... and I have to think that a 5 line "trick" is going to wind
up being more straight-forward and maintainable than 2,200 lines of near
duplicate SQL.
...


sounds like you have a view and a view with a predicate

if
open c for select * from v;
else
open c for select * from v where date...;

I don't like tricks, tricks get lost in history - no one knows why they are there. what happens when the optimizer decides in 11.1.0.17 that a difference of one on the index cost adjust is not meaningful - they are the same (I'm forecasting what might happen)
5 stars Food for thought   June 16, 2008 - 2pm Central time zone
Reviewer: Matthew McPeak 
It would be more like 18 views, but I see your point.  Thank you again!






All information and materials provided here are provided "as-is"; Oracle disclaims all express and implied warranties, including, the implied warranties of merchantability or fitness for a particular use. Oracle shall not be liable for any damages, including, direct, indirect, incidental, special or consequential damages for loss of profits, revenue, data or data use, incurred by you or any third party in connection with the use of this information or these materials.

About Oracle | Legal Notices and Terms of Use | Privacy Statement