Before, I have found the ‘Cost’ in the execution plan to be a good indicator of relative execution time. Why is this case different? Am I a fool for thinking the execution plan has relevance? What specifically can I try to improve v_test performance?
Thank you.
Using Oracle 10g I have a simple query view defined below
create or replace view v_test as select distinct u.bo_id as bo_id, upper(trim(d.dept_id)) as dept_id from cust_bo_users u join cust_bo_roles r on u.role_name=r.role_name join cust_dept_roll_up_tbl d on (r.region is null or trim(r.region)=trim(d.chrgback_reg)) and (r.prod_id is null or trim(r.prod_id)=trim(d.prod_id)) and (r.div_id is null or trim(r.div_id)=trim(d.div_id )) and (r.clus_id is null or trim(r.clus_id )=trim( d.clus_id)) and (r.prod_ln_id is null or trim(r.prod_ln_id)=trim(d.prod_ln_id)) and (r.dept_id is null or trim(r.dept_id)=trim(d.dept_id))
defined to replace the following view
create or replace view v_bo_secured_detail select distinct Q.BO_ID, Q.DEPT_ID from (select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'REGION' and trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) union all select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'RG_PROD' and trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) and trim(R.PROD_ID) = UPPER(trim(D.PROD_ID)) union all select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'PROD' and trim(R.PROD_ID) = UPPER(trim(D.PROD_ID)) union all select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'DIV' and trim(R.DIV_ID) = UPPER(trim(D.DIV_ID)) union all select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'RG_DIV' and trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) and trim(R.DIV_ID) = UPPER(trim(D.DIV_ID)) union all select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'CLUS' and trim(R.CLUS_ID) = UPPER(trim(D.CLUS_ID)) union all select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'RG_CLUS' and trim(R.REGION) = UPPER(trim(D.CHRGBACK_REG)) and trim(R.CLUS_ID) = UPPER(trim(D.CLUS_ID)) union all select U.BO_ID BO_ID, UPPER(trim(D.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R, CUST_DEPT_ROLL_UP_TBL D where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'PROD_LN' and trim(R.PROD_LN_ID) = UPPER(trim(D.PROD_LN_ID)) union all select U.BO_ID BO_ID, UPPER(trim(R.DEPT_ID)) DEPT_ID from CUST_BO_USERS U, CUST_BO_ROLES R where U.ROLE_NAME = R.ROLE_NAME and R.ROLE_LEVEL = 'DEPT') Q
with the goal of removing the dependency on the ROLE_LEVEL column.
The execution plan for v_test is significantly lower than v_bo_secured_detail for simple
select * from <view> where bo_id='value'
queries. And is significantly lower when used in a real world query
select CT_REPORT.RPT_KEY, CT_REPORT_ENTRY.RPE_KEY, CT_REPORT_ENTRY.CUSTOM16, Exp_Sub_Type.value, min(CT_REPORT_PAYMENT_CONF.PAY_DATE), CT_REPORT.PAID_DATE from CT_REPORT, <VIEW> SD, CT_REPORT_ENTRY, CT_LIST_ITEM_LANG Exp_Sub_Type, CT_REPORT_PAYMENT_CONF, CT_STATUS_LANG Payment_Status where (CT_REPORT_ENTRY.RPT_KEY = CT_REPORT.RPT_KEY) and (Payment_Status.STAT_KEY = CT_REPORT.PAY_KEY) and (Exp_Sub_Type.LI_KEY = CT_REPORT_ENTRY.CUSTOM9 and Exp_Sub_Type.LANG_CODE = 'en') and (CT_REPORT.RPT_KEY = CT_REPORT_PAYMENT_CONF.RPT_KEY) and (SD.BO_ID = 'JZHU9') and (SD.DEPT_ID = UPPER(CT_REPORT_ENTRY.CUSTOM5)) and (Payment_Status.name = 'Payment Confirmed' and (Payment_Status.LANG_CODE = 'en') and CT_REPORT.PAID_DATE > to_date('01/01/2008', 'mm/dd/yyyy') and Exp_Sub_Type.value != 'Korea') group by CT_REPORT.RPT_KEY, CT_REPORT_ENTRY.RPE_KEY, CT_REPORT_ENTRY.CUSTOM16, Exp_Sub_Type.value, CT_REPORT.PAID_DATE
The execution times are WILDLY different. The v_test view taking 15 hours, and the v_bo_secured_detail taking a few seconds.
Thank you all who responded
This is one to remember for me. The places where the theory and mathematics of the expressions meets the reality of hardware based execution. Ouch.
As the Oracle documentation says, the cost is the estimated cost relative to a particular execution plan. When you tweak the query, the particular execution plan that costs are calculated relative to can change. Sometimes dramatically.
The problem with v_test’s performance is that Oracle can think of no way to execute it other than performing a nested loop, for each cust_bo_roles, scan all of cust_dept_roll_up_tbl to find a match. If the table are of size n and m, this takes n*m time, which is slow for large tables. By contrast v_bo_secured_detail is set up so that it is a series of queries, each of which can be done through some other mechanism. (Oracle has a number it may use, including using an index, building a hash on the fly, or sorting the datasets and merging them. These operations are all O(n*log(n)) or better.) A small series of fast queries is fast.
As painful as it is, if you want this query to be fast then you need to break it out like the previous query did.