Thanks
Chris, March 18, 2005 - 2:02 pm UTC
Most appreciated. We'll resort to using the hint until we can patch - even though it's not on the good hint list ;-)
March 18, 2005 - 2:38 pm UTC
(or use the DATE type...)
Ah but...
Chris, March 18, 2005 - 3:51 pm UTC
I'd like to use the date type in this type of situation, but i thought this wasn't possible when using application contexts.
March 18, 2005 - 8:07 pm UTC
ahh, well that whole "bind variable peeking" thing isn't going to happen with sys_context at all.
Jeff Beal, March 18, 2005 - 5:30 pm UTC
Thanks for responding to this, Tom. I ran into this problem several months ago, and wasn't able to find any definitive information on it. Now, I've run into it again. I had guessed from what I had been seeing that this bind parameter peeking was the culprit.
I do have an interesting wrinkle to this one.
My starting query is
select patient_visit.patient_visit_rsn, patients.birthdate
from patients, patient_visit
where patient_visit.patient_rsn = patients.patient_rsn
and (patients.birthdate >=
to_date('1977-12-19','yyyy-mm-dd')
and patients.birthdate <
to_date('1977-12-20','yyyy-mm-dd'))
This takes about six seconds to run
Using the literal DATE value, I get my answer back (345 rows) practically instantly.
On a whim, I created my own my_to_date function:
It looks like this:
CREATE FUNCTION "RADWARE"."MY_TO_DATE" (dateStr IN VARCHAR2,
formatStr IN VARCHAR2)
RETURN DATE IS
BEGIN
RETURN to_date(dateStr,formatStr);
END;
When the query uses this function instead of the builtin to_date() function, I get results back in the same amount of time as with the DATE literal.
How is there a difference between my function and the built-in Oracle function?
March 18, 2005 - 8:14 pm UTC
i'm not following you here. does the query take 6 seconds or run instantly?
Jeff Beal, March 18, 2005 - 9:17 pm UTC
The query as written takes six seconds.
If I replace every occurrence of the to_date function with the DATE 'yyyy-mm-dd' syntax, it returns instantly.
If I replace every occurrence of the to_date function with the my_to_date function, it returns instantly.
March 19, 2005 - 6:49 am UTC
I'm not understanding you. show both queries.
This statement:
If I replace every occurrence of the to_date function with the DATE 'yyyy-mm-dd'
syntax, it returns instantly.
does not compute.
compare the plans as well -- what are the plans at the end of the day.
follow-up to an OTN thread ...
Gabe, March 18, 2005 - 11:16 pm UTC
Jeff:
If you're still running with cursor_sharing=similar then better mention that to save Tom from having to diagnose it himself ... sorry to interject, but that setting is rather relevant.
Custom function behaves differently
Jeff Beal, March 21, 2005 - 11:08 am UTC
Sorry about the confusion, Tom. Let me try one more time to see if I can make myself clear. First, as Gabe pointed out, I am using CURSOR_SHARING=SIMILAR. Sorry I didn't mention that before.
Now, here are the queries that I'm working with, including execution time and execution plan (from TKPROF, not EXPLAIN PLAN):
Query 1:
select patient_visit.patient_visit_rsn, patients.birthdate
from patients, patient_visit
where patient_visit.patient_rsn = patients.patient_rsn
and (patients.birthdate >=
to_date('1977-12-19','yyyy-mm-dd')
and patients.birthdate <
to_date('1977-12-20','yyyy-mm-dd'));
Exec. Time: 7.766 seconds
Rows Row Source Operation
------- ---------------------------------------------------
345 FILTER
345 TABLE ACCESS BY INDEX ROWID PATIENT_VISIT
551 NESTED LOOPS
205 VIEW
205 HASH JOIN
205 INDEX RANGE SCAN IX_PATIENTS_BIRTHDATE (object id 108091)
5029424 INDEX FAST FULL SCAN PK_PATIENTS (object id 108081)
345 INDEX RANGE SCAN IX_FK_PATIENT_VISIT_1 (object id 97460)
Query 2:
select patient_visit.patient_visit_rsn, patients.birthdate
from patients, patient_visit
where patient_visit.patient_rsn = patients.patient_rsn
and (patients.birthdate >= DATE '1977-12-19'
and patients.birthdate < DATE '1977-12-20');
Exec. Time: 0.047 seconds
Rows Row Source Operation
------- ---------------------------------------------------
345 TABLE ACCESS BY INDEX ROWID PATIENT_VISIT
551 NESTED LOOPS
205 TABLE ACCESS BY INDEX ROWID PATIENTS
205 INDEX RANGE SCAN IX_PATIENTS_BIRTHDATE (object id 108091)
345 INDEX RANGE SCAN IX_FK_PATIENT_VISIT_1 (object id 97460)
Query 3 (using the my_to_date function that I included above):
select patient_visit.patient_visit_rsn, patients.birthdate
from patients, patient_visit
where patient_visit.patient_rsn = patients.patient_rsn
and (patients.birthdate >=
my_to_date('1977-12-19','yyyy-mm-dd')
and patients.birthdate <
my_to_date('1977-12-20','yyyy-mm-dd'));
Exec. Time: 0.047 seconds
Rows Row Source Operation
------- ---------------------------------------------------
345 TABLE ACCESS BY INDEX ROWID PATIENT_VISIT
551 NESTED LOOPS
205 TABLE ACCESS BY INDEX ROWID PATIENTS
205 INDEX RANGE SCAN IX_PATIENTS_BIRTHDATE (object id 108091)
345 INDEX RANGE SCAN IX_FK_PATIENT_VISIT_1 (object id 97460)
Obviously, the performance difference between Query 1 and Query 2 is caused by the FAST FULL SCAN on the PK_PATIENTS index. Based on your original answer in this article, I can understand how "bind peeking" affects the execution plans in these two queries. What I do *not* understand is how the optimizer "gets it right" for Query #3. How is there a difference between my function and the built-in Oracle function?
March 22, 2005 - 10:51 am UTC
do you know what cursor sharing similar does?
it binds...
where col <op> function(:bind)
no bind peeking...
where col <op> :bind
bind peeking - probably the same thing as above -- search for 10053 and check out the estimated cardinalities between the two -- it'll probably show "lots" and that would confirm this.
Custom function behaves differently
Jeff Beal, March 22, 2005 - 1:37 pm UTC
Yes, I do know what CURSOR_SHARING=SIMILAR does. Getting rid of it is somewhere on my to-do list ;) Thanks for your original answer that clearly explained what was going on with the difference between Query 1 and Query 2.
I set the 10053 event, and ran the queries again, and the trace file revealed the difference between Query 1 and Query 3:
No statistics type defined for function MY_TO_DATE
No default cost defined for function MY_TO_DATE
Now I understand enough of what's going on to get on with my work.
Thanks!
March 22, 2005 - 6:04 pm UTC
forget your function for a minute, between literal without function and literal with to_date() on it, just compare the estimated cardinalities from the row sources.
Join cardinalities
Jeff Beal, March 23, 2005 - 10:36 am UTC
I'm not too familiar with how to read 10053 trace files, so forgive me if I give you the wrong numbers. I found the 'Join Cardinality' numbers for the three queries. Query 1 and Query 3 had the same cardinality: 27477. Query 3's cardinality was much lower: 147.
Thanks again for your help
Custom function behaves differently
Jeff Beal, March 24, 2005 - 12:24 pm UTC
We won't be using the user defined 'my_to_date' function in our application. It was just something that I had tried out while trying to figure out why Query 1 and Query 2 were behaving so differently. Thanks for the pointer to the artical on associating statistics with functions, though. That will probably come in handy down the road.