Recompute plan each time for the sql [message #415372] |
Mon, 27 July 2009 08:11 |
prachij593
Messages: 266 Registered: May 2009
|
Senior Member |
|
|
Can we force the optimizer, to recompute a plan each time for a select query that uses so many bind variables?
In the sql, the where predicate is build dynamically.
Thanks,
Prachi
|
|
|
|
Re: Recompute plan each time for the sql [message #415378 is a reply to message #415375] |
Mon, 27 July 2009 08:34 |
JRowbottom
Messages: 5933 Registered: June 2006 Location: Sunny North Yorkshire, ho...
|
Senior Member |
|
|
Building the Where clause dynamically will cause a hard parse for each different where clause that gets built.
Why would you want to force a parse when one is not neccessary - of have you misunderstood what the parse step is for?
|
|
|
Re: Recompute plan each time for the sql [message #415379 is a reply to message #415378] |
Mon, 27 July 2009 08:45 |
prachij593
Messages: 266 Registered: May 2009
|
Senior Member |
|
|
Sir,
Below is the sql build dynamically based on input.
I need your suggesion if we can do better with such kinda sql, by forcing optimizer to rebuild a plan each time for this sql.
SELECT *
FROM (
SELECT
ROWNUM RN,
Q.*
FROM (
SELECT 1,
C.CSID,
E.PNME ,
L.DSC ,
E.IN_TMS ,
E.IN_TMS ,
R.VLAST_NME ,
R.VFIRST_NME ,
R.VP_CDE ,
R.CST_NBR ,
R.CLAST_NME ,
R.PCFIRST_NME ,
R.DRUG_NME ,
R.TR_NBR ,
R.RC_NBR ,
C.CS_I_ID
FROM PF F, TR R, OTM N, CSIT C, WP E, CDM L
WHERE E.SID = C.CSID
AND E.STYPE= 'C'
AND R.OID = F.OID
AND F.C_ID = N.SID
AND F.CIS_NBR = N.SUB_SID
AND R.OID = C.PRID
AND E.LID = '07'
AND E.PNME NOT IN ('TRN')
AND L.CTXT_ID = E.PNME
AND L.QTXT = 'B347'
AND (((((E.IN1_TMS BETWEEN TO_DATE(NULL, 'mm/dd/yyyy hh:mi:ss am') AND TO_DATE(NULL, 'mm/dd/yyyy hh:mi:ss am')
AND NULL IS NULL )
OR (E.IN2_TMS BETWEEN TO_DATE(NULL, 'mm/dd/yyyy hh:mi:ss am') AND TO_DATE(NULL, 'mm/dd/yyyy hh:mi:ss am')
AND NULL IS NOT NULL ))
AND ((UPPER(NULL )) IS NULL
OR ((UPPER(R.VLAST_NME)) LIKE (UPPER(NULL ))||'%')
OR ((UPPER(NULL )) IS NULL
AND (UPPER(R.VLAST_NME)) IS NULL))
AND ((UPPER(NULL )) IS NULL
OR ((UPPER(R.VFIRST_NME)) LIKE (UPPER(NULL ))||'%')
OR ((UPPER(NULL )) IS NULL
AND (UPPER(R.VFIRST_NME)) IS NULL))
AND ((UPPER(NULL )) IS NULL
OR ((UPPER(R.VP_CDE)) LIKE (UPPER(NULL ))||'%')
OR ((UPPER(NULL )) IS NULL
AND (UPPER(R.VP_CDE)) IS NULL))
AND ((UPPER(NULL )) IS NULL
OR ((UPPER(R.CLAST_NME)) LIKE (UPPER(NULL ))||'%')
OR ((UPPER(NULL )) IS NULL
AND (UPPER(R.CLAST_NME)) IS NULL))
AND ((UPPER(NULL )) IS NULL
OR ((UPPER(R.CFIRST_NME)) LIKE (UPPER(NULL ))||'%')
OR ((UPPER(NULL )) IS NULL
AND ((UPPER(NULL )) IS NULL
OR ((UPPER(R.CST_NBR)) LIKE (UPPER(NULL ))||'%')
OR ((UPPER(NULL )) IS NULL
AND (UPPER(R.CST_NBR)) IS NULL))))
OR C.CS_I_ID = NULL
OR C.CSID = 786987652
OR R.TR_NBR = NULL
OR R.RC_NBR = NULL )
AND F.C_ID = N.SID
AND F.CIS_NBR = N.SUB_SID
AND N.LAST_TMS = GET_MX_TMS(N.SID, N.S_SID
)
AND ((N.DEST_ID) = E.PNME
OR (N.DEST_ID) LIKE '%NIK')
AND F.C_ID = GET_MX_F(C.CS_I_ID)
ORDER BY E.IN_TMS, L.DSC DESC) Q
WHERE ROWNUM <= 100 )
WHERE RN >= 10
[Updated on: Mon, 27 July 2009 08:54] Report message to a moderator
|
|
|
|
|
|
Re: Recompute plan each time for the sql [message #415458 is a reply to message #415433] |
Mon, 27 July 2009 23:32 |
rleishman
Messages: 3728 Registered: October 2005 Location: Melbourne, Australia
|
Senior Member |
|
|
I suspect all of the NULLs are actually bind variables, which have been replaced manually in order to run the SQL in a client.
I further suspect that you have this hooked up to a parameter screen and want to solve many problems with one SQL:
- Select everything when no parameters are entered.
- When one or more parameters are entered, optimise the SQL according to the entered parameter.
This method has been tried and failed by many before you. I can be done in limited cases by using OR predicates and a hint to transform internally to a UNION query. This method stops working effectively when there are many parameters and complex conditions - probably true of you query.
The alternative is to work out a few optimal access paths (full scan for no params, index on CS_I_ID when supplied) and create sepeate SQLs for each one. Then in your code - depending on the params supplied - you choose the appropriate SQL.
You could also upgrade to 11g, which has bind-variable re-peeking.
Ross Leishman
|
|
|
|
|
Re: Recompute plan each time for the sql [message #415604 is a reply to message #415587] |
Tue, 28 July 2009 06:08 |
prachij593
Messages: 266 Registered: May 2009
|
Senior Member |
|
|
Quote: |
Why are you generating a statement with all these unnecessary conditions?
|
The conditions passed are not unnecessary
Quote: |
- Select everything when no parameters are entered.
- When one or more parameters are entered, optimise the SQL according to the entered parameter.
|
|
|
|
Re: Recompute plan each time for the sql [message #415617 is a reply to message #415372] |
Tue, 28 July 2009 06:56 |
michael_bialik
Messages: 621 Registered: July 2006
|
Senior Member |
|
|
...
AND ((UPPER(NULL )) IS NULL
OR ((UPPER(R.VLAST_NME)) LIKE (UPPER(NULL ))||'%')
OR ((UPPER(NULL )) IS NULL
AND (UPPER(R.VLAST_NME)) IS NULL))...
If I got it right:
When NO value is supplied then you DON'T have to generate the condition.
HTH
|
|
|
|
|
|
Re: Recompute plan each time for the sql [message #416184 is a reply to message #415970] |
Fri, 31 July 2009 00:47 |
|
Kevin Meade
Messages: 2103 Registered: December 1999 Location: Connecticut USA
|
Senior Member |
|
|
I am thinking also that there is more to this than we are being told. Maybe I missed it, but there are no joins between the tables that I see in this where clause. Hard to optimize a query when you do not have the full query.
However, you could also try using a table function for this. Then you get something like from clause courtesy of the collection type and table function:
create object o_rrowtype as (c1 ...,c2...,...,cn ...)
/
create object c_rrowtype as table of o_rrowtype
/
from e
, c
, cast(tf(:p1,:p2,...,:pn) as c_rrowtype) r
and then inside the table function you can dynamically construct a query that does whole object assignement and return your collection of rows via execute immediate. It would force your query to be parsed each time because you are doing dynamic sql, thus affording you an opportunity to get the best plan possible for the parameters supplied, and there would be no need at all for any of the "did not supply parameter(x) so put in this dummy expression" junk in the where clause.
function tf(p1...,p2...,pn...) return c_rrowtype is
c_rrowtype_v c_rrowtype;
sqlv varchar2(32000);
begin
--
-- dynamically construct a sqlstatement that does whole object assignement
-- then execute it, returning results into your collection variable
--
if p1 is not null then <add it to where clause> end if;
...
if pn is not null then ... end if;
execute immediate sql_v into c_rrowtype_v;
return (c_rrowtype_v);
end;
/
whole object assignment is where you cast a select statment into a collection type and then stuff it into a variable based on that type. something like this:
select cast(multiset(select * from(
select *
from t
where ...
)
) as c_rrowtype
)
into c_rrowtype_v
from dual
;
your dynamic sql will be the select statement in the middle of this thing.
Forgive me if my syntax for execute immediate is off. I often forget the different between returning, into, using etc. Also, the seemingly worthless (select * from( in the above is a fix I found for multicast that does not like comlex selects. The need to use it varies between Oracle versions.
Good luck, Kevin
|
|
|