CBO + View
Hi all.
So, I get many servers with Oracle 9208 + SLES 9.4
I have view :
CREATE OR REPLACE FORCE VIEW SA.V_FULL_DSPEC
(ID, DOCUMENT_ID, DEPTFR_ID, DEPTTO_ID, ARTICLE_ID,
INCLUDE_ID, QTY, SALE_PRICE, BOSS_PRICE, PRICE,
ORDER_NUM, QTY_REAL, PRICE_TYPE, BOSS_PRICE_TYPE, EXT_CODE,
QTY_REAL_CONFIRM, PACKAGE_ID, VAT_ID)
AS
SELECT /*+ INDEX (E_DSPEC) */
ID
,Document_id
,Deptfr_id
,Deptto_id
,Article_id
,Include_id
,Qty
,Sale_price
,Boss_price
,Price
,Order_num
,Qty_real
,Price_type
,Boss_price_type
,Ext_code
,qty_real_confirm
,package_id
,vat_id
FROM E_dspec
UNION ALL
SELECT /*+ INDEX (ARC_DSPEC) */
ID
,Document_id
,Deptfr_id
,Deptto_id
,Article_id
,Include_id
,Qty
,Sale_price
,Boss_price
,Price
,Order_num
,Qty_real
,Price_type
,Boss_price_type
,Ext_code
,qty_real_confirm
,package_id
,vat_id
FROM Arc_dspec;
Each table have more than 1 milion rows.
And have some query, that using this view.
So, I have srvers 2 groups : A and B
On server group A I have one execution plan of this query
On server group B I have other execution plan of this query, not like on server group A.
Difference between plans are wery big
If I change table sequence in view for server group B, i've get plan like on group A
But if I change table sequence in view for server group A, plan don't change.
Performance of query on server group A good, on server group B bad ((
Query do not change on any server group.
I can't understand, that the change of sequence can change the plan?
If you need more info, tel me.
server group A Execution Plan
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=114438 Card=1 Bytes=263)
1 0 NESTED LOOPS (Cost=2 Card=1 Bytes=25)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'L_INCLUDE' (Cost=1 Card=1 Bytes=16)
3 2 INDEX (RANGE SCAN) OF 'I_LINCLUDE_ARTICLEID' (NON-UNIQUE) (Cost=3 Card=1)
4 1 TABLE ACCESS (BY INDEX ROWID) OF 'D_INCLUDE' (Cost=1 Card=1 Bytes=9)
5 4 INDEX (UNIQUE SCAN) OF 'PK_D_INCLUDE' (UNIQUE)
6 0 SORT (ORDER BY) (Cost=114438 Card=1 Bytes=263)
7 6 SORT (GROUP BY) (Cost=114438 Card=1 Bytes=263)
8 7 FILTER
9 8 NESTED LOOPS (Cost=114404 Card=1 Bytes=263)
10 9 MERGE JOIN (CARTESIAN) (Cost=114403 Card=1 Bytes=189)
11 10 NESTED LOOPS (Cost=114402 Card=1 Bytes=185)
12 11 NESTED LOOPS (Cost=114145 Card=5 Bytes=660)
13 12 NESTED LOOPS (Cost=2 Card=1 Bytes=99)
14 13 TABLE ACCESS (BY INDEX ROWID) OF 'D_DEPT' (Cost=1 Card=1 Bytes=44)
15 14 INDEX (UNIQUE SCAN) OF 'PK_D_DEPT' (UNIQUE) (Cost=1 Card=1)
16 13 TABLE ACCESS (BY INDEX ROWID) OF 'D_DEPT' (Cost=1 Card=1 Bytes=55)
17 16 INDEX (UNIQUE SCAN) OF 'PK_D_DEPT' (UNIQUE)
18 12 VIEW OF 'V_FULL_DHEAD' (Cost=114143 Card=5 Bytes=165)
19 18 UNION-ALL
20 19 FILTER
21 20 TABLE ACCESS (BY INDEX ROWID) OF 'E_DHEAD' (Cost=11 Card=2 Bytes=48)
22 21 INDEX (RANGE SCAN) OF 'IDX_E_DHEAD_DOC_DATE' (NON-UNIQUE) (Cost=6 Card=776)
23 19 FILTER
24 23 PARTITION RANGE (ITERATOR)
25 24 PARTITION LIST (INLIST)
26 25 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'ARC_DHEAD' (Cost=1012 Card=34150 Bytes=819600)
27 26 INDEX (RANGE SCAN) OF 'I_AHEAD_DOC_DATE_' (NON-UNIQUE) (Cost=793 Card=184412)
28 11 VIEW OF 'V_FULL_DSPEC' (Cost=52 Card=1 Bytes=53)
29 28 UNION-ALL (PARTITION)
30 29 TABLE ACCESS (BY GLOBAL INDEX ROWID) OF 'ARC_DSPEC' (Cost=1 Card=1 Bytes=27)
31 30 INDEX (RANGE SCAN) OF 'I_ADSPEC_DOCUMENT_ID' (NON-UNIQUE) (Cost=4 Card=6)
32 29 TABLE ACCESS (BY INDEX ROWID) OF 'E_DSPEC' (Cost=1 Card=1 Bytes=27)
33 32 INDEX (RANGE SCAN) OF 'I_DSPEC_DOCUMENT_ID' (NON-UNIQUE) (Cost=3 Card=9)
34 10 BUFFER (SORT) (Cost=114351 Card=4 Bytes=16)
35 34 INDEX (RANGE SCAN) OF 'DEPT_FIRM_FK2' (NON-UNIQUE)
36 9 TABLE ACCESS (BY INDEX ROWID) OF 'D_ARTICLE' (Cost=1 Card=1 Bytes=74)
37 36 INDEX (UNIQUE SCAN) OF 'D_ARTICLE_PK' (UNIQUE)
38 36 TABLE ACCESS (BY INDEX ROWID) OF 'D_ARTICLE' (Cost=1 Card=1 Bytes=26)
39 38 INDEX (UNIQUE SCAN) OF 'D_ARTICLE_PK' (UNIQUE) (Cost=2 Card=1)
40 39 TABLE ACCESS (FULL) OF 'DUAL' (Cost=2 Card=82)
41 36 TABLE ACCESS (BY INDEX ROWID) OF 'D_ARTICLE' (Cost=1 Card=1 Bytes=26)
42 41 INDEX (UNIQUE SCAN) OF 'D_ARTICLE_PK' (UNIQUE) (Cost=2 Card=1)
43 42 TABLE ACCESS (FULL) OF 'DUAL' (Cost=2 Card=82)
server group B Execution Plan
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1259 Card=1 Bytes=259)
1 0 NESTED LOOPS (Cost=2 Card=1 Bytes=25)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'L_INCLUDE' (Cost=1 Card=1 Bytes=16)
3 2 INDEX (RANGE SCAN) OF 'I_LINCLUDE_ARTICLEID' (NON-UNIQUE) (Cost=3 Card=1)
4 1 TABLE ACCESS (BY INDEX ROWID) OF 'D_INCLUDE' (Cost=1 Card=1 Bytes=9)
5 4 INDEX (UNIQUE SCAN) OF 'PK_D_INCLUDE' (UNIQUE)
6 0 SORT (ORDER BY) (Cost=1259 Card=1 Bytes=259)
7 6 SORT (GROUP BY) (Cost=1259 Card=1 Bytes=259)
8 7 FILTER
9 8 MERGE JOIN (CARTESIAN) (Cost=1242 Card=1 Bytes=259)
10 9 NESTED LOOPS (Cost=1241 Card=1 Bytes=255)
11 10 NESTED LOOPS (Cost=1203 Card=383 Bytes=85026)
12 11 NESTED LOOPS (Cost=1024 Card=1787 Bytes=302003)
13 12 NESTED LOOPS (Cost=2 Card=1 Bytes=95)
14 13 TABLE ACCESS (BY INDEX ROWID) OF 'D_DEPT' (Cost=1 Card=1 Bytes=42)
15 14 INDEX (UNIQUE SCAN) OF 'PK_D_DEPT' (UNIQUE) (Cost=1 Card=1)
16 13 TABLE ACCESS (BY INDEX ROWID) OF 'D_DEPT' (Cost=1 Card=1 Bytes=53)
17 16 INDEX (UNIQUE SCAN) OF 'PK_D_DEPT' (UNIQUE)
18 12 TABLE ACCESS (FULL) OF 'D_ARTICLE' (Cost=1022 Card=1787 Bytes=132238)
19 18 TABLE ACCESS (BY INDEX ROWID) OF 'D_ARTICLE' (Cost=1 Card=1 Bytes=26)
20 19 INDEX (UNIQUE SCAN) OF 'D_ARTICLE_PK' (UNIQUE) (Cost=2 Card=1)
21 20 TABLE ACCESS (FULL) OF 'DUAL' (Cost=11 Card=8168)
22 18 TABLE ACCESS (BY INDEX ROWID) OF 'D_ARTICLE' (Cost=1 Card=1 Bytes=26)
23 22 INDEX (UNIQUE SCAN) OF 'D_ARTICLE_PK' (UNIQUE) (Cost=2 Card=1)
24 23 TABLE ACCESS (FULL) OF 'DUAL' (Cost=11 Card=8168)
25 11 VIEW OF 'V_FULL_DSPEC' (Cost=1 Card=1 Bytes=53)
26 25 UNION-ALL (PARTITION)
27 26 TABLE ACCESS (BY INDEX ROWID) OF 'E_DSPEC' (Cost=1 Card=1 Bytes=28)
28 27 INDEX (RANGE SCAN) OF 'I_DSPEC_ARTICLE_ID' (NON-UNIQUE) (Cost=1 Card=16)
29 26 PARTITION RANGE (ALL)
30 29 PARTITION LIST (ALL)
31 30 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'ARC_DSPEC' (Cost=50 Card=1 Bytes=27)
32 31 INDEX (RANGE SCAN) OF 'I_ASPEC_ARTICLE_ID' (NON-UNIQUE) (Cost=82 Card=528)
33 10 VIEW OF 'V_FULL_DHEAD' (Cost=1 Card=1 Bytes=33)
34 33 UNION-ALL (PARTITION)
35 34 FILTER
36 35 TABLE ACCESS (BY INDEX ROWID) OF 'E_DHEAD' (Cost=1 Card=1 Bytes=24)
37 36 INDEX (UNIQUE SCAN) OF 'PK_E_DHEAD' (UNIQUE) (Cost=1 Card=1)
38 34 FILTER
39 38 TABLE ACCESS (BY GLOBAL INDEX ROWID) OF 'ARC_DHEAD' (Cost=1 Card=1 Bytes=24)
40 39 INDEX (UNIQUE SCAN) OF 'I_ARC_HEAD_ID' (UNIQUE) (Cost=2 Card=1)
41 9 BUFFER (SORT) (Cost=1258 Card=4 Bytes=16)
42 41 INDEX (RANGE SCAN) OF 'UK_L_DEPT_FIRM' (NON-UNIQUE) (Cost=1 Card=4 Bytes=16)
The amount of data on both server group are close and same.
Statistic gather every day, with dbms_stats.gather_schema_stats(); on each server (group A and B) And dba_tables view show that the statistic have been gathered.
I have try to use hints but get another plan from group server A. And all this plan are very slow to, like on server group B.
I try to experement with session parameter:
OPTIMIZER_INDEX_COST_ADJ
OPTIMIZER_INDEX_CACHING
DB_FILE_MULTIBLOCK_READ_COUNT
SORT_AREA_SIZE
But no one of them didn't change the plan on server group B (i don't use stored outlines)
So why? I have same Oracle, same OS, same DB and clase data, but plan is not the same...
Edited by: HuliGUN on 19.07.2010 23:01
Edited by: HuliGUN on 19.07.2010 23:10
Similar Messages
-
View joining two spatial tables and strange CBO behaviour
Hi all,
I've following view in my database:
CREATE OR REPLACE VIEW my_view AS
SELECT id, 'table1' AS source, location FROM my_table1
UNION ALL
SELECT id, 'table2' AS source, location FROM my_table2;
When I execute query:
SELECT * FROM my_view WHERE SDO_RELATE(location, SDO_GEOMETRY(...), 'mask=anyinteract') = 'TRUE';
It works as expected.
When running query like (getting location with subquery):
SELECT * FROM my_view WHERE SDO_RELATE(location, (SELECT location FROM my_table3 WHERE id = 123, 'mask=anyinteract') = 'TRUE';
It doesn't work. Oracle Throws "DatabaseError: ORA-13226: interface not supported without a spatial index"
Further investigation revealed strange behaviour of CBO:
In first case Oracle CBO uses Spatial index just fine and as expected.
But second query and CBO get's a bit strange - unique index scan is used for subselect, but for view tables is full table scan is used and SDO_RELATE is not happy with that since no spatial index is used.
How I can use spatial indexes regardless of that subselect?Hi folks,
Looking over these responses and not finding a lot of clarity yet in terms of leaving a trail for future readers to glean an answer from. I was just looking through the back-and-forth and curious myself about the issue First of all I think Jani's observations are quite on target. This CBO reaction is weird and does not work they way most Oracle users would expect it to work. Secondly, Jani really should tell us his Oracle version and folks providing answers should as well - the CBO is always being tweaked. Thirdly, Stefan provides a solution though it's a rather expensive solution to my taste. And finally, I think we as a group need to spend a bit more time reproducing things in code. I will give it a shot, feel free to correct anything I got wrong.
So first of all, I wrote this up quick on 12.1.0.2 and verified it was the same on 11.2.0.4
DROP TABLE my_table1 PURGE;
CREATE TABLE my_table1(
objectid INTEGER NOT NULL
,tsource VARCHAR2(30 Char)
,shape MDSYS.SDO_GEOMETRY
,PRIMARY KEY(objectid)
DROP TABLE my_table2 PURGE;
CREATE TABLE my_table2(
objectid INTEGER NOT NULL
,tsource VARCHAR2(30 Char)
,shape MDSYS.SDO_GEOMETRY
,PRIMARY KEY(objectid)
DROP TABLE my_table3 PURGE;
CREATE TABLE my_table3(
objectid INTEGER NOT NULL
,tsource VARCHAR2(30 Char)
,shape MDSYS.SDO_GEOMETRY
,PRIMARY KEY(objectid)
CREATE OR REPLACE PROCEDURE seeder(
p_count IN NUMBER
AS
sdo_foo MDSYS.SDO_GEOMETRY;
int_counter NUMBER := 1;
FUNCTION random_line
RETURN MDSYS.SDO_GEOMETRY
AS
num_x1 NUMBER;
num_y1 NUMBER;
num_offx NUMBER;
num_offy NUMBER;
BEGIN
num_x1 := dbms_random.value(-179,179);
num_y1 := dbms_random.value(-89,89);
RETURN MDSYS.SDO_GEOMETRY(
2002
,8265
,NULL
,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1)
,MDSYS.SDO_ORDINATE_ARRAY(
num_x1
,num_y1
,num_x1 + 0.0001
,num_y1 + 0.0001
END random_line;
BEGIN
FOR i IN 1 .. p_count
LOOP
sdo_foo := random_line();
INSERT INTO my_table1
VALUES (
int_counter
,'table1'
,sdo_foo
int_counter := int_counter + 1;
sdo_foo := random_line();
INSERT INTO my_table2
VALUES (
int_counter
,'table2'
,sdo_foo
int_counter := int_counter + 1;
sdo_foo := random_line();
INSERT INTO my_table3
VALUES (
int_counter
,'table3'
,sdo_foo
int_counter := int_counter + 1;
END LOOP;
INSERT INTO my_table1
VALUES (
0
,'table1'
,MDSYS.SDO_GEOMETRY(
2002
,8265
,NULL
,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1)
,MDSYS.SDO_ORDINATE_ARRAY(
-87.8211111
,42.5847222
,-87.8212
,42.5848
INSERT INTO my_table3
VALUES (
0
,'table3'
,MDSYS.SDO_GEOMETRY(
2002
,8265
,NULL
,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1)
,MDSYS.SDO_ORDINATE_ARRAY(
-87.8211111
,42.5848
,-87.8212
,42.5847222
COMMIT;
END seeder;
BEGIN
seeder(100000);
END;
SELECT 'my_table1: ' || COUNT(*) AS invalid_count FROM my_table1 WHERE MDSYS.SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(shape,0.05) <> 'TRUE'
UNION ALL
SELECT 'my_table2: ' || COUNT(*) AS invalid_count FROM my_table2 WHERE MDSYS.SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(shape,0.05) <> 'TRUE'
UNION ALL
SELECT 'my_table3: ' || COUNT(*) AS invalid_count FROM my_table3 WHERE MDSYS.SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT(shape,0.05) <> 'TRUE';
BEGIN
INSERT INTO user_sdo_geom_metadata(
table_name
,column_name
,diminfo
,srid
) VALUES (
'MY_TABLE1'
,'SHAPE'
,MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',-180,180,.05),MDSYS.SDO_DIM_ELEMENT('Y',-90,90,.05))
,8265
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
BEGIN
INSERT INTO user_sdo_geom_metadata(
table_name
,column_name
,diminfo
,srid
) VALUES (
'MY_TABLE2'
,'SHAPE'
,MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',-180,180,.05),MDSYS.SDO_DIM_ELEMENT('Y',-90,90,.05))
,8265
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
BEGIN
INSERT INTO user_sdo_geom_metadata(
table_name
,column_name
,diminfo
,srid
) VALUES (
'MY_TABLE3'
,'SHAPE'
,MDSYS.SDO_DIM_ARRAY(MDSYS.SDO_DIM_ELEMENT('X',-180,180,.05),MDSYS.SDO_DIM_ELEMENT('Y',-90,90,.05))
,8265
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
CREATE INDEX my_table1_spx ON my_table1
(shape)
INDEXTYPE IS MDSYS.SPATIAL_INDEX
NOPARALLEL;
CREATE INDEX my_table2_spx ON my_table2
(shape)
INDEXTYPE IS MDSYS.SPATIAL_INDEX
NOPARALLEL;
CREATE INDEX my_table3_spx ON my_table3
(shape)
INDEXTYPE IS MDSYS.SPATIAL_INDEX
NOPARALLEL;
BEGIN
dbms_stats.gather_table_stats(USER, 'MY_TABLE1');
dbms_stats.gather_index_stats(USER, 'MY_TABLE1_SPX');
dbms_stats.gather_table_stats(USER, 'MY_TABLE2');
dbms_stats.gather_index_stats(USER, 'MY_TABLE2_SPX');
dbms_stats.gather_table_stats(USER, 'MY_TABLE3');
dbms_stats.gather_index_stats(USER, 'MY_TABLE3_SPX');
END;
CREATE OR REPLACE VIEW my_view
AS
SELECT
objectid
,'table1' AS tsource
,shape
FROM
my_table1
UNION ALL
SELECT
objectid
,'table2' AS tsource
,shape
FROM my_table2;
set timing on;
-- QUERY #1
-- Jani's original setup, works as expected
SELECT
COUNT(*) AS single_geom_counter
FROM
my_view a
WHERE
MDSYS.SDO_RELATE(
a.shape
,MDSYS.SDO_GEOMETRY(
2002
,8265
,NULL
,MDSYS.SDO_ELEM_INFO_ARRAY(1,2,1)
,MDSYS.SDO_ORDINATE_ARRAY(
-87.8211111
,42.5848
,-87.8212
,42.5847222
,'mask=anyinteract'
) = 'TRUE';
-- QUERY #2
-- Now the problem statement
SELECT
COUNT(*) AS table_problem_counter
FROM
my_view a
WHERE
MDSYS.SDO_RELATE(
a.shape
,(SELECT b.shape FROM my_table3 b WHERE b.objectid = 0)
,'mask=anyinteract'
) = 'TRUE';
-- QUERY #3
-- Stefan's solution
SELECT /*+ ORDERED */
COUNT(*) AS stefans_solution
FROM
my_table3 a
,my_view b
WHERE
a.objectid = 0
AND MDSYS.SDO_RELATE(
a.shape
,b.shape
,'mask=anyinteract'
) = 'TRUE';
Anyhow, so the hard coded query #1 that Jani provided works exactly the way most folks would expect, the second item in the relate is applied to each spatial index participating in the view. I think we can agree this is what we want.
Now when we move on to the problem, well its all goes off the rails as I think its looks to apply the spatial filter to the view itself which lacks an index (not sure really)
So as Stefan says, you can work around this by rewriting things as query #3 does above though now its a full table scan of both tables in the view. This is a long way performance wise from Query #1!
So on my 12c test box
query #1 Elapsed: 00:00:00.016
query #3 Elapsed: 00:00:33.534
On 11g production box
query #1 Elapsed: 00:00:00.49
query #3 Elapsed: 00:02:31.45 (ouch!)
So hopefully someone else can jump in with more information on better solutions?
I overall tend to avoid the kind of unioned views that Jani is using here. I have a hard time recalling why but I must have been burned similarly many years ago when I was first starting with Oracle spatial. I tend to always want my spatial indexes right there where I can keep a grim stink eye on them. It may be that a unioned view with multiple spatial indexes behind it might just be a bad practice better done with a materialized view? Or maybe a lesser term? Unprofitable practice? fraught? "Best if you don't do that"?
Anyhow, I would be interested in what others have as input on the matter.
Cheers,
Paul -
Using a variable in a view?
I know that it may not be possible to use a variable within a view, but I'm wondering if there isn't a work-around? If there is a single value---pulled from another table---you wish to reuse in a view that does not use dynamic SQL, how do you do so? I've been toying around with WITH statements, but that's getting me nowhere. I'm using 11r2.
BTW, please do not ask me the standard litany of angry-dba questions (why are you doing this? your database is f*****, RTFM, etc.), this is just for my own curiosity. :)
Thank you
Example for demo purposes only (I know it's not syntactically correct):
variable var_value varchar2(30)
begin
select this_is_just_one_value
int :var_value
from tableX where column1 = 'BOB';
end;
select
numerous_columns
from tableY
where
column5 = :var_value;893968 wrote:
BTW, please do not ask me the standard litany of angry-dba questions (why are you doing this? your database is f*****, RTFM, etc.), this is just for my own curiosity. :)Why are you doing this? your database is f*****! RTFM! Etc!! ;-)
SQL is not a procedural language - so you cannot create a view for example that has a parameter signature. E.g. this is possible in a procedural language:
declare
cursor c( deptID number ) is
select * from emp where deptno = deptID;
begin
open c( 1234 ); --// open SQL cursor using a parameter/variable
--// etc..
close c;
end;This is not possible using a SQL object like a view. As a view is not a procedure. So the same approach as the above using SQL (silly example, but do demonstrates the basics):
// define
create or replace view emp_view as select * from emp;
// use
select * from emp_view where deptno = 1234;The CBO is clever - and it will likely push such a predicate into the emp_view SQL statement.
To parameterise such a view, is ugly. And should only be considered when dealing with issues such as security and data restrictions. A context is created - this can contain a number of name-values. The view can then use a name-value from the context. Oracle's data dictionary views use this approach. -
CBO generating different plans for the same data in similar Environments
Hi All
I have been trying to compare an SQL from 2 different but similar environments build of the same hardware specs .The issue I am facing is environment A, the query executes in less than 2 minutes with plan mostly showing full table scans and hash join whereas in environment B(problematic), it times out after 2 hours with an error of unable to extend table space . The statistics are up to date in both environments for both tables and indexes . System parameters are exactly similar(default oracle for except for multiblock_read_count ).
Both Environment have same db parameter for db_file_multiblock_read_count(16), optimizer(refer below),hash_area_size (131072),pga_aggregate_target(1G),db_block_size(8192) etc . SREADTIM, MREADTIM, CPUSPEED, MBRC are all null in aux_stats in both environment because workload was never collected i believe.
Attached is details about the SQL with table stats, SQL and index stats my main concern is CBO generating different plans for the similar data and statistics and same hardware and software specs. Is there any thing else I should consider .I generally see environment B being very slow and always plans tend to nested loops and index scan whereas what we really need is a sensible FTS in many cases. One of the very surprising thing is METER_CONFIG_HEADER below which has just 80 blocks of data is being asked for index scan.
show parameter optimizer
optimizer_dynamic_sampling integer 2
optimizer_features_enable string 10.2.0.4
optimizer_index_caching integer 0
optimizer_index_cost_adj integer 100
optimizer_mode string ALL_ROWS
optimizer_secure_view_merging boolean TRUE
**Environment**
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for Solaris: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production
Note: : There are slight difference in the no of records in the attached sheet.However, I wanted to tell that i have tested with exact same data and was getting similar results but I couldn't retain the data untill collecting the details in the attachment
TEST1 COMPARE TABLE LEVE STATS used by CBO
ENVIRONMENT A
TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED
ASSET 3607425 167760 5/02/2013 22:11
METER_CONFIG_HEADER 3658 80 5/01/2013 0:07
METER_CONFIG_ITEM 32310 496 5/01/2013 0:07
NMI 1899024 33557 18/02/2013 10:55
REGISTER 4830153 101504 18/02/2013 9:57
SDP_LOGICAL_ASSET 1607456 19137 18/02/2013 15:48
SDP_LOGICAL_REGISTER 5110781 78691 18/02/2013 9:56
SERVICE_DELIVERY_POINT 1425890 42468 18/02/2013 13:54
ENVIRONMENT B
TABLE_NAME NUM_ROWS BLOCKS LAST_ANALYZED
ASSET 4133939 198570 16/02/2013 10:02
METER_CONFIG_HEADER 3779 80 16/02/2013 10:55
METER_CONFIG_ITEM 33720 510 16/02/2013 10:55
NMI 1969000 33113 16/02/2013 10:58
REGISTER 5837874 120104 16/02/2013 11:05
SDP_LOGICAL_ASSET 1788152 22325 16/02/2013 11:06
SDP_LOGICAL_REGISTER 6101934 91088 16/02/2013 11:07
SERVICE_DELIVERY_POINT 1447589 43804 16/02/2013 11:11
TEST ITEM 2 COMPARE INDEX STATS used by CBO
ENVIRONMENT A
TABLE_NAME INDEX_NAME UNIQUENESS BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR NUM_ROWS
ASSET IDX_AST_DEVICE_CATEGORY_SK NONUNIQUE 2 9878 67 147 12982 869801 3553095
ASSET IDX_A_SAPINTLOGDEV_SK NONUNIQUE 2 7291 2747 2 639 1755977 3597916
ASSET SYS_C00102592 UNIQUE 2 12488 3733831 1 1 3726639 3733831
METER_CONFIG_HEADER SYS_C0092052 UNIQUE 1 12 3670 1 1 3590 3670
METER_CONFIG_ITEM SYS_C0092074 UNIQUE 1 104 32310 1 1 32132 32310
NMI IDX_NMI_ID NONUNIQUE 2 6298 844853 1 2 1964769 1965029
NMI IDX_NMI_ID_NK NONUNIQUE 2 6701 1923072 1 1 1922831 1923084
NMI IDX_NMI_STATS NONUNIQUE 1 106 4 26 52 211 211
REGISTER REG_EFFECTIVE_DTM NONUNIQUE 2 12498 795 15 2899 2304831 4711808
REGISTER SYS_C00102653 UNIQUE 2 16942 5065660 1 1 5056855 5065660
SDP_LOGICAL_ASSET IDX_SLA_SAPINTLOGDEV_SK NONUNIQUE 2 3667 1607968 1 1 1607689 1607982
SDP_LOGICAL_ASSET IDX_SLA_SDP_SK NONUNIQUE 2 3811 668727 1 2 1606204 1607982
SDP_LOGICAL_ASSET SYS_C00102665 UNIQUE 2 5116 1529606 1 1 1528136 1529606
SDP_LOGICAL_REGISTER SYS_C00102677 UNIQUE 2 17370 5193638 1 1 5193623 5193638
SERVICE_DELIVERY_POINT IDX_SDP_NMI_SK NONUNIQUE 2 4406 676523 1 2 1423247 1425890
SERVICE_DELIVERY_POINT IDX_SDP_SAP_INT_NMI_SK NONUNIQUE 2 7374 676523 1 2 1458238 1461108
SERVICE_DELIVERY_POINT SYS_C00102687 UNIQUE 2 4737 1416207 1 1 1415022 1416207
ENVIRONMENT B
TABLE_NAME INDEX_NAME UNIQUENESS BLEVEL LEAF_BLOCKS DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR NUM_ROWS
ASSET IDX_AST_DEVICE_CATEGORY_SK NONUNIQUE 2 8606 121 71 16428 1987833 4162257
ASSET IDX_A_SAPINTLOGDEV_SK NONUNIQUE 2 8432 1780146 1 1 2048170 4162257
ASSET SYS_C00116157 UNIQUE 2 13597 4162263 1 1 4158759 4162263
METER_CONFIG_HEADER SYS_C00116570 UNIQUE 1 12 3779 1 1 3734 3779
METER_CONFIG_ITEM SYS_C00116592 UNIQUE 1 107 33720 1 1 33459 33720
NMI IDX_NMI_ID NONUNIQUE 2 6319 683370 1 2 1970460 1971313
NMI IDX_NMI_ID_NK NONUNIQUE 2 6597 1971293 1 1 1970771 1971313
NMI IDX_NMI_STATS NONUNIQUE 1 98 48 2 4 196 196
REGISTER REG_EFFECTIVE_DTM NONUNIQUE 2 15615 1273 12 2109 2685924 5886582
REGISTER SYS_C00116748 UNIQUE 2 19533 5886582 1 1 5845565 5886582
SDP_LOGICAL_ASSET IDX_SLA_SAPINTLOGDEV_SK NONUNIQUE 2 4111 1795084 1 1 1758441 1795130
SDP_LOGICAL_ASSET IDX_SLA_SDP_SK NONUNIQUE 2 4003 674249 1 2 1787987 1795130
SDP_LOGICAL_ASSET SYS_C004520 UNIQUE 2 5864 1795130 1 1 1782147 1795130
SDP_LOGICAL_REGISTER SYS_C004539 UNIQUE 2 20413 6152850 1 1 6073059 6152850
SERVICE_DELIVERY_POINT IDX_SDP_NMI_SK NONUNIQUE 2 3227 660649 1 2 1422572 1447803
SERVICE_DELIVERY_POINT IDX_SDP_SAP_INT_NMI_SK NONUNIQUE 2 6399 646257 1 2 1346948 1349993
SERVICE_DELIVERY_POINT SYS_C00128706 UNIQUE 2 4643 1447946 1 1 1442796 1447946
TEST ITEM 3 COMPARE PLANS
ENVIRONMENT A
Plan hash value: 4109575732
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 13 | 2067 | | 135K (2)| 00:27:05 |
| 1 | HASH UNIQUE | | 13 | 2067 | | 135K (2)| 00:27:05 |
|* 2 | HASH JOIN | | 13 | 2067 | | 135K (2)| 00:27:05 |
|* 3 | HASH JOIN | | 6 | 900 | | 135K (2)| 00:27:04 |
|* 4 | HASH JOIN ANTI | | 1 | 137 | | 135K (2)| 00:27:03 |
|* 5 | TABLE ACCESS BY INDEX ROWID| NMI | 1 | 22 | | 5 (0)| 00:00:01 |
| 6 | NESTED LOOPS | | 1 | 131 | | 95137 (2)| 00:19:02 |
|* 7 | HASH JOIN | | 1 | 109 | | 95132 (2)| 00:19:02 |
|* 8 | TABLE ACCESS FULL | ASSET | 36074 | 1021K| | 38553 (2)| 00:07:43 |
|* 9 | HASH JOIN | | 90361 | 7059K| 4040K| 56578 (2)| 00:11:19 |
|* 10 | HASH JOIN | | 52977 | 3414K| 2248K| 50654 (2)| 00:10:08 |
|* 11 | HASH JOIN | | 39674 | 1782K| | 40101 (2)| 00:08:02 |
|* 12 | TABLE ACCESS FULL | REGISTER | 39439 | 1232K| | 22584 (2)| 00:04:32 |
|* 13 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 4206K| 56M| | 17490 (2)| 00:03:30 |
|* 14 | TABLE ACCESS FULL | SERVICE_DELIVERY_POINT | 675K| 12M| | 9412 (2)| 00:01:53 |
|* 15 | TABLE ACCESS FULL | SDP_LOGICAL_ASSET | 1178K| 15M| | 4262 (2)| 00:00:52 |
|* 16 | INDEX RANGE SCAN | IDX_NMI_ID_NK | 2 | | | 2 (0)| 00:00:01 |
| 17 | VIEW | | 39674 | 232K| | 40101 (2)| 00:08:02 |
|* 18 | HASH JOIN | | 39674 | 1046K| | 40101 (2)| 00:08:02 |
|* 19 | TABLE ACCESS FULL | REGISTER | 39439 | 500K| | 22584 (2)| 00:04:32 |
|* 20 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 4206K| 56M| | 17490 (2)| 00:03:30 |
|* 21 | TABLE ACCESS FULL | METER_CONFIG_HEADER | 3658 | 47554 | | 19 (0)| 00:00:01 |
|* 22 | TABLE ACCESS FULL | METER_CONFIG_ITEM | 7590 | 68310 | | 112 (2)| 00:00:02 |
Predicate Information (identified by operation id):
2 - access("METER_CONFIG_HEADER_SK"="METER_CONFIG_HEADER_SK")
3 - access("NETWORK_TARIFF_CD"="NETWORK_TARIFF_CD")
4 - access("SERVICE_DELIVERY_POINT_SK"="TMP"."SERVICE_DELIVERY_POINT_SK")
5 - filter("ROW_CURRENT_IND"='Y' AND ("NMI_STATUS_CD"='A' OR "NMI_STATUS_CD"='D'))
7 - access("ASSET_CD"="EQUIP_CD" AND "SAP_INT_LOG_DEVICE_SK"="SAP_INT_LOG_DEVICE_SK")
8 - filter("ROW_CURRENT_IND"='Y')
9 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK")
10 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK")
11 - access("SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
12 - filter("REGISTER_TYPE_CD"='C' AND (SUBSTR("REGISTER_ID_CD",1,1)='4' OR
SUBSTR("REGISTER_ID_CD",1,1)='5' OR SUBSTR("REGISTER_ID_CD",1,1)='6') AND "ROW_CURRENT_IND"='Y')
13 - filter("ROW_CURRENT_IND"='Y')
14 - filter("ROW_CURRENT_IND"='Y')
15 - filter("ROW_CURRENT_IND"='Y')
16 - access("NMI_SK"="NMI_SK")
18 - access("SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
19 - filter("REGISTER_TYPE_CD"='C' AND (SUBSTR("REGISTER_ID_CD",1,1)='1' OR
SUBSTR("REGISTER_ID_CD",1,1)='2' OR SUBSTR("REGISTER_ID_CD",1,1)='3') AND "ROW_CURRENT_IND"='Y')
20 - filter("ROW_CURRENT_IND"='Y')
21 - filter("ROW_CURRENT_IND"='Y')
22 - filter("ROW_CURRENT_IND"='Y' AND "CONROL_REGISTER"='X')
ENVIRONMENT B
Plan hash value: 2826260434
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 181 | 103K (2)| 00:20:47 |
| 1 | HASH UNIQUE | | 1 | 181 | 103K (2)| 00:20:47 |
|* 2 | HASH JOIN ANTI | | 1 | 181 | 103K (2)| 00:20:47 |
|* 3 | HASH JOIN | | 1 | 176 | 56855 (2)| 00:11:23 |
|* 4 | HASH JOIN | | 1 | 163 | 36577 (2)| 00:07:19 |
|* 5 | TABLE ACCESS BY INDEX ROWID | ASSET | 1 | 44 | 4 (0)| 00:00:01 |
| 6 | NESTED LOOPS | | 1 | 131 | 9834 (2)| 00:01:59 |
| 7 | NESTED LOOPS | | 1 | 87 | 9830 (2)| 00:01:58 |
| 8 | NESTED LOOPS | | 1 | 74 | 9825 (2)| 00:01:58 |
|* 9 | HASH JOIN | | 1 | 52 | 9820 (2)| 00:01:58 |
|* 10 | TABLE ACCESS BY INDEX ROWID| METER_CONFIG_HEADER | 1 | 14 | 1 (0)| 00:00:01 |
| 11 | NESTED LOOPS | | 1 | 33 | 116 (2)| 00:00:02 |
|* 12 | TABLE ACCESS FULL | METER_CONFIG_ITEM | 1 | 19 | 115 (2)| 00:00:02 |
|* 13 | INDEX RANGE SCAN | SYS_C00116570 | 1 | | 1 (0)| 00:00:01 |
|* 14 | TABLE ACCESS FULL | SERVICE_DELIVERY_POINT | 723K| 13M| 9699 (2)| 00:01:57 |
|* 15 | TABLE ACCESS BY INDEX ROWID | NMI | 1 | 22 | 5 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IDX_NMI_ID_NK | 2 | | 2 (0)| 00:00:01 |
|* 17 | TABLE ACCESS BY INDEX ROWID | SDP_LOGICAL_ASSET | 1 | 13 | 5 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | IDX_SLA_SDP_SK | 2 | | 2 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | IDX_A_SAPINTLOGDEV_SK | 2 | | 2 (0)| 00:00:01 |
|* 20 | TABLE ACCESS FULL | REGISTER | 76113 | 2378K| 26743 (2)| 00:05:21 |
|* 21 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 5095K| 63M| 20245 (2)| 00:04:03 |
| 22 | VIEW | | 90889 | 443K| 47021 (2)| 00:09:25 |
|* 23 | HASH JOIN | | 90889 | 2307K| 47021 (2)| 00:09:25 |
|* 24 | TABLE ACCESS FULL | REGISTER | 76113 | 966K| 26743 (2)| 00:05:21 |
|* 25 | TABLE ACCESS FULL | SDP_LOGICAL_REGISTER | 5095K| 63M| 20245 (2)| 00:04:03 |
Predicate Information (identified by operation id):
2 - access("SERVICE_DELIVERY_POINT_SK"="TMP"."SERVICE_DELIVERY_POINT_SK")
3 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK" AND
"SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
4 - access("ASSET_CD"="EQUIP_CD")
5 - filter("ROW_CURRENT_IND"='Y')
9 - access("NETWORK_TARIFF_CD"="NETWORK_TARIFF_CD")
10 - filter("ROW_CURRENT_IND"='Y')
12 - filter("ROW_CURRENT_IND"='Y' AND "CONROL_REGISTER"='X')
13 - access("METER_CONFIG_HEADER_SK"="METER_CONFIG_HEADER_SK")
14 - filter("ROW_CURRENT_IND"='Y')
15 - filter("ROW_CURRENT_IND"='Y' AND ("NMI_STATUS_CD"='A' OR "NMI_STATUS_CD"='D'))
16 - access("NMI_SK"="NMI_SK")
17 - filter("ROW_CURRENT_IND"='Y')
18 - access("SERVICE_DELIVERY_POINT_SK"="SERVICE_DELIVERY_POINT_SK")
19 - access("SAP_INT_LOG_DEVICE_SK"="SAP_INT_LOG_DEVICE_SK")
20 - filter((SUBSTR("REGISTER_ID_CD",1,1)='4' OR SUBSTR("REGISTER_ID_CD",1,1)='5' OR
SUBSTR("REGISTER_ID_CD",1,1)='6') AND "REGISTER_TYPE_CD"='C' AND "ROW_CURRENT_IND"='Y')
21 - filter("ROW_CURRENT_IND"='Y')
23 - access("SAP_INT_LOGICAL_REGISTER_SK"="SAP_INT_LOGICAL_REGISTER_SK")
24 - filter((SUBSTR("REGISTER_ID_CD",1,1)='1' OR SUBSTR("REGISTER_ID_CD",1,1)='2' OR
SUBSTR("REGISTER_ID_CD",1,1)='3') AND "REGISTER_TYPE_CD"='C' AND "ROW_CURRENT_IND"='Y')
25 - filter("ROW_CURRENT_IND"='Y')Edited by: abhilash173 on Feb 24, 2013 9:16 PM
Edited by: abhilash173 on Feb 24, 2013 9:18 PMHi Paul,
I misread your question initially .The system stats are outdated in both ( same result as seen from aux_stats) .I am not a DBA and do not have access to gather system stats fresh.
select * from sys.aux_stats$
SNAME PNAME PVAL1 PVAL2
SYSSTATS_INFO STATUS NULL COMPLETED
SYSSTATS_INFO DSTART NULL 02-16-2011 15:24
SYSSTATS_INFO DSTOP NULL 02-16-2011 15:24
SYSSTATS_INFO FLAGS 1 NULL
SYSSTATS_MAIN CPUSPEEDNW 1321.20523 NULL
SYSSTATS_MAIN IOSEEKTIM 10 NULL
SYSSTATS_MAIN IOTFRSPEED 4096 NULL
SYSSTATS_MAIN SREADTIM NULL NULL
SYSSTATS_MAIN MREADTIM NULL NULL
SYSSTATS_MAIN CPUSPEED NULL NULL
SYSSTATS_MAIN MBRC NULL NULL
SYSSTATS_MAIN MAXTHR NULL NULL
SYSSTATS_MAIN SLAVETHR NULL NULL -
[oracle 10.2.0.4] My view is not merged
Hi,
I have a view which is not merged by the CBO. I mean the CBO decides to apply the filter predicate after the execution of the view.
Here is the definition of the view
CREATE OR REPLACE VIEW VUNSCP AS
SELECT X.DASFM,X.COINT,X.NUCPT,X.RGCOD,X.RGCID,X.CODEV,X.CTDEV,X.CDVRF,X.TXCHJ,X.MTNLV,X.MTVDP,
LEAD(X.MTNLV+X.MTVDP,1) OVER (PARTITION BY X.COINT,X.NUCPT,X.CDVRF,X.CTDEV,X.CODEV,X.RGCOD,X.RGCID ORDER BY X.DASFM DESC),
SUM(X.MTNLV) OVER (PARTITION BY X.COINT,X.CODEV,X.RGCOD)
FROM SFMCPT XThe query is:
explain plan for
select * from VUNSCP where dasfm='30-apr-10';
select * from table(dbms_xplan.display);
Plan hash value: 2545326530
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 13M| 1529M| | 195K (1)| 00:39:11 |
|* 1 | VIEW | VUNSCP | 13M| 1529M| | 195K (1)| 00:39:11 |
| 2 | WINDOW SORT | | 13M| 646M| 1996M| 195K (1)| 00:39:11 |
| 3 | TABLE ACCESS FULL| SFMCPT | 13M| 646M| | 27991 (4)| 00:05:36 |
Predicate Information (identified by operation id):
1 - filter("DASFM"='30-apr-10')You can see that a FTS is performed on SFMCPT (>1 million of rows) and that the filter predicate is applied only after the view has been instantiated.
So the index on DASFM can't be used.
This query is returning about 30 000 rows. We see on the plan that the CBO is mistaken beacause it reckons that there's going to be 13M of rows.
If I add the filter predicate directly on the view'script I get the correct plan:
explain plan for
SELECT X.DASFM,X.COINT,X.NUCPT,X.RGCOD,X.RGCID,X.CODEV,X.CTDEV,X.CDVRF,X.TXCHJ,X.MTNLV,X.MTVDP,
LEAD(X.MTNLV+X.MTVDP,1) OVER (PARTITION BY X.COINT,X.NUCPT,X.CDVRF,X.CTDEV,X.CODEV,X.RGCOD,X.RGCID ORDER BY X.DASFM DESC),
SUM(X.MTNLV) OVER (PARTITION BY X.COINT,X.CODEV,X.RGCOD)
FROM SFMCPT X where dasfm='30-apr-10';
select * from table(dbms_xplan.display);
Plan hash value: 1865390099
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 14357 | 729K| 13271 (1)| 00:02:40 |
| 1 | WINDOW SORT | | 14357 | 729K| 13271 (1)| 00:02:40 |
| 2 | TABLE ACCESS BY INDEX ROWID| SFMCPT | 14357 | 729K| 13269 (1)| 00:02:40 |
|* 3 | INDEX RANGE SCAN | SFMCPT1 | 14357 | | 67 (0)| 00:00:01 |
Predicate Information (identified by operation id):
3 - access("DASFM"='30-apr-10')The index is now used and the rows estimated seem closer to the actual rows.
I tried several things:
- disabling the "OPTIMZER_COST_BASED_TRANSFORMATION" hidden parameter
- use the MERGE hint
- alter session set optimizer_features_enable = '9.2.0.8';
All these workarounds don't work => I'm still getting the bad execution plan.
According to Jonathan LEWIS' s book the 9i optimzer always merge views But here even if I set the optimizer_features_enable parameter to 9i the view is not merged.
It's sure that the issue is due to the analytical functions but why ?
Can please someone help me to understand what is going on ?
Edited by: Ahmed AANGOUR on 5 mai 2010 08:41here is the 10053 trace file:
/oracle/app/oracle/admin/UBIXPROD/udump/ubixprod_ora_24971_10053_optimizer_trace.trc
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
ORACLE_HOME = /oracle/app/oracle/10.2.0
System name: Linux
Node name: lin-ubi-test1.ubitrade.com
Release: 2.6.9-78.0.1.ELsmp
Version: #1 SMP Tue Jul 22 18:01:05 EDT 2008
Machine: x86_64
Instance name: UBIXPROD
Redo thread mounted by this instance: 1
Oracle process number: 26
*** 2010-05-04 12:14:51.450
*** ACTION NAME:() 2010-05-04 12:14:51.450
*** MODULE NAME:([email protected] (TNS V1-V3)) 2010-05-04 12:14:51.450
*** SERVICE NAME:(SYS$USERS) 2010-05-04 12:14:51.450
*** SESSION ID:(135.1512) 2010-05-04 12:14:51.450
Registered qb: SEL$1 0xa9e139a8 (PARSER)
signature (): qb_name=SEL$1 nbfros=1 flg=0
fro(0): flg=5 objn=297481 hint_alias="VUNSCP"@"SEL$1"
Registered qb: SEL$2 0xa9e0bdd0 (PARSER)
signature (): qb_name=SEL$2 nbfros=1 flg=0
fro(0): flg=4 objn=265023 hint_alias="X"@"SEL$2"
Predicate Move-Around (PM)
PM: Considering predicate move-around in SEL$1 (#0).
PM: Checking validity of predicate move-around in SEL$1 (#0).
CBQT: Validity checks failed for 3xakq94fcx4td.
CVM: Considering view merge in query block SEL$1 (#0)
CVM: Checking validity of merging SEL$2 (#0)
CVM: Considering view merge in query block SEL$2 (#0)
CVM: CVM bypassed: Window functions in this view
CBQT: Validity checks failed for 3xakq94fcx4td.
Subquery Unnest
SU: Considering subquery unnesting in query block SEL$1 (#0)
Set-Join Conversion (SJC)
SJC: Considering set-join conversion in SEL$1 (#0).
Set-Join Conversion (SJC)
SJC: Considering set-join conversion in SEL$2 (#0).
Predicate Move-Around (PM)
PM: Considering predicate move-around in SEL$1 (#0).
PM: Checking validity of predicate move-around in SEL$1 (#0).
PM: Passed validity checks.
FPD: Considering simple filter push in SEL$1 (#0)
FPD: Current where clause predicates in SEL$1 (#0) :
"VUNSCP"."DASFM"='30-apr-10'
kkogcp: try to generate transitive predicate from check constraints for SEL$1 (#0)
predicates with check contraints: "VUNSCP"."DASFM"='30-apr-10'
after transitive predicate generation: "VUNSCP"."DASFM"='30-apr-10'
finally: "VUNSCP"."DASFM"='30-apr-10'
JPPD: JPPD bypassed: View not on right-side of outer join
FPD: Considering simple filter push in SEL$2 (#0)
FPD: Current where clause predicates in SEL$2 (#0) :
apadrv-start: call(in-use=2936, alloc=16344), compile(in-use=38784, alloc=44568)
kkoqbc-start
: call(in-use=2936, alloc=16344), compile(in-use=40472, alloc=44568)
kkoqbc-subheap (create addr=0x2a9740c1f0)
Current SQL statement for this session:
EXPLAIN PLAN FOR select * from VUNSCP where dasfm='30-apr-10'
Peeked values of the binds in SQL statement
PARAMETERS USED BY THE OPTIMIZER
PARAMETERS WITH ALTERED VALUES
_pga_max_size = 262140 KB
cursor_sharing = similar
_optimizer_cost_based_transformation = off
Column Usage Monitoring is ON: tracking level = 1
QUERY BLOCK TEXT
EXPLAIN PLAN FOR select * from VUNSCP where dasfm='30-apr-10'
QUERY BLOCK SIGNATURE
qb name was generated
signature (optimizer): qb_name=SEL$2 nbfros=1 flg=0
fro(0): flg=0 objn=265023 hint_alias="X"@"SEL$2"
SYSTEM STATISTICS INFORMATION
Using NOWORKLOAD Stats
CPUSPEED: 2503 millions instruction/sec
IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
IOSEEKTIM: 10 milliseconds (default is 10)
BASE STATISTICAL INFORMATION
Table Stats::
Table: SFMCPT Alias: X
#Rows: 13036040 #Blks: 122880 AvgRowLen: 358.00
Index Stats::
Index: SFMCPT1 Col#: 2 3 4 8 5 7 118
LVLS: 2 #LB: 58758 #DK: 13013072 LB/K: 1.00 DB/K: 1.00 CLUF: 11983641.00
Index: SFMCPT2 Col#: 1
LVLS: 2 #LB: 30031 #DK: 13483987 LB/K: 1.00 DB/K: 1.00 CLUF: 2410599.00
Index: SFMCPT3 Col#: 3 4 8 5 7 2 118
LVLS: 2 #LB: 39065 #DK: 13013072 LB/K: 1.00 DB/K: 1.00 CLUF: 12583891.00
SINGLE TABLE ACCESS PATH
BEGIN Single Table Cardinality Estimation
Table: SFMCPT Alias: X
Card: Original: 13036040 Rounded: 13036040 Computed: 13036040.00 Non Adjusted: 13036040.00
END Single Table Cardinality Estimation
Access Path: TableScan
Cost: 27991.05 Resp: 27991.05 Degree: 0
Cost_io: 26881.00 Cost_cpu: 33334822147
Resp_io: 26881.00 Resp_cpu: 33334822147
Best:: AccessPath: TableScan
Cost: 27991.05 Degree: 1 Resp: 27991.05 Card: 13036040.00 Bytes: 0
OPTIMIZER STATISTICS AND COMPUTATIONS
GENERAL PLANS
Considering cardinality-based initial join order.
Permutations for Starting Table :0
Join order[1]: SFMCPT[X]#0
WiF sort
SORT resource Sort statistics
Sort width: 766 Area size: 1048576 Max Area size: 134215680
Degree: 1
Blocks to Sort: 108528 Row size: 68 Total Rows: 13036040
Initial runs: 7 Merge passes: 1 IO Cost / pass: 58786
Total IO sort cost: 167314 Total CPU sort cost: 16584848017
Total Temp space used: 2093966000
Best so far: Table#: 0 cost: 195857.3183 card: 13036040.0000 bytes: 677874080
(newjo-stop-1) k:0, spcnt:0, perm:1, maxperm:80000
Number of join permutations tried: 1
SORT resource Sort statistics
Sort width: 766 Area size: 1048576 Max Area size: 134215680
Degree: 1
Blocks to Sort: 108528 Row size: 68 Total Rows: 13036040
Initial runs: 7 Merge passes: 1 IO Cost / pass: 58786
Total IO sort cost: 167314 Total CPU sort cost: 16584848017
Total Temp space used: 2093966000
Final - All Rows Plan: Best join order: 1
Cost: 195857.3183 Degree: 1 Card: 13036040.0000 Bytes: 677874080
Resc: 195857.3183 Resc_io: 194195.0000 Resc_cpu: 49919670164
Resp: 195857.3183 Resp_io: 194195.0000 Resc_cpu: 49919670164
kkoipt: Query block SEL$2 (#0)
******* UNPARSED QUERY IS *******
SELECT "X"."DASFM" "DASFM","X"."COINT" "COINT","X"."NUCPT" "NUCPT","X"."RGCOD" "RGCOD","X"."RGCID" "RGCID","X"."CODEV" "CODEV","X"."CTDEV" "CTDEV","X"."CDVRF" "CDVRF","X"."TXCHJ" "TXCHJ","X"."MTNLV" "MTNLV","X"."MTVDP" "MTVDP",DECODE(COUNT(*) OVER ( PARTITION BY "X"."COINT","X"."CODEV","X"."RGCOD","X"."CTDEV","X"."NUCPT","X"."CDVRF","X"."RGCID" ORDER BY "X"."DASFM" DESC ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING ),1,FIRST_VALUE("X"."MTNLV"+"X"."MTVDP") OVER ( PARTITION BY "X"."COINT","X"."CODEV","X"."RGCOD","X"."CTDEV","X"."NUCPT","X"."CDVRF","X"."RGCID" ORDER BY "X"."DASFM" DESC ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING ),NULL) "MTUNS",SUM("X"."MTNLV") OVER ( PARTITION BY "X"."COINT","X"."CODEV","X"."RGCOD") "MTNLI" FROM "SFMCPT" "X"
kkoqbc-subheap (delete addr=0x2a9740c1f0, in-use=11856, alloc=12408)
kkoqbc-end
: call(in-use=57760, alloc=81816), compile(in-use=41096, alloc=44568)
kkoqbc-start
: call(in-use=57760, alloc=81816), compile(in-use=41184, alloc=44568)
kkoqbc-subheap (create addr=0x2a9746b058)
QUERY BLOCK TEXT
select * from VUNSCP where dasfm='30-apr-10'
QUERY BLOCK SIGNATURE
qb name was generated
signature (optimizer): qb_name=SEL$1 nbfros=1 flg=0
fro(0): flg=1 objn=297481 hint_alias="VUNSCP"@"SEL$1"
SYSTEM STATISTICS INFORMATION
Using NOWORKLOAD Stats
CPUSPEED: 2503 millions instruction/sec
IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
IOSEEKTIM: 10 milliseconds (default is 10)
BASE STATISTICAL INFORMATION
Table Stats::
Table: VUNSCP Alias: VUNSCP (NOT ANALYZED)
#Rows: 0 #Blks: 0 AvgRowLen: 0.00
OPTIMIZER STATISTICS AND COMPUTATIONS
GENERAL PLANS
Considering cardinality-based initial join order.
Permutations for Starting Table :
Join order[1]: VUNSCP[VUNSCP]#0
Best so far: Table#: 0 cost: 195857.3183 card: 13036040.0000 bytes: 1603432920
(newjo-stop-1) k:0, spcnt:0, perm:1, maxperm:80000
Number of join permutations tried: 1
Final - All Rows Plan: Best join order: 1
Cost: 195857.3183 Degree: 1 Card: 13036040.0000 Bytes: 1603432920
Resc: 195857.3183 Resc_io: 194195.0000 Resc_cpu: 49919670164
Resp: 195857.3183 Resp_io: 194195.0000 Resc_cpu: 49919670164
kkoipt: Query block SEL$1 (#0)
******* UNPARSED QUERY IS *******
SELECT "VUNSCP"."DASFM" "DASFM","VUNSCP"."COINT" "COINT","VUNSCP"."NUCPT" "NUCPT","VUNSCP"."RGCOD" "RGCOD","VUNSCP"."RGCID" "RGCID","VUNSCP"."CODEV" "CODEV","VUNSCP"."CTDEV" "CTDEV","VUNSCP"."CDVRF" "CDVRF","VUNSCP"."TXCHJ" "TXCHJ","VUNSCP"."MTNLV" "MTNLV","VUNSCP"."MTVDP" "MTVDP","VUNSCP"."MTUNS" "MTUNS","VUNSCP"."MTNLI" "MTNLI" FROM (SELECT "X"."DASFM" "DASFM","X"."COINT" "COINT","X"."NUCPT" "NUCPT","X"."RGCOD" "RGCOD","X"."RGCID" "RGCID","X"."CODEV" "CODEV","X"."CTDEV" "CTDEV","X"."CDVRF" "CDVRF","X"."TXCHJ" "TXCHJ","X"."MTNLV" "MTNLV","X"."MTVDP" "MTVDP",DECODE(COUNT(*) OVER ( PARTITION BY "X"."COINT","X"."CODEV","X"."RGCOD","X"."CTDEV","X"."NUCPT","X"."CDVRF","X"."RGCID" ORDER BY "X"."DASFM" DESC ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING ),1,FIRST_VALUE("X"."MTNLV"+"X"."MTVDP") OVER ( PARTITION BY "X"."COINT","X"."CODEV","X"."RGCOD","X"."CTDEV","X"."NUCPT","X"."CDVRF","X"."RGCID" ORDER BY "X"."DASFM" DESC ROWS BETWEEN 1 FOLLOWING AND 1 FOLLOWING ),NULL) "MTUNS",SUM("X"."MTNLV") OVER ( PARTITION BY "X"."COINT","X"."CODEV","X"."RGCOD") "MTNLI" FROM "SFMCPT" "X") "VUNSCP" WHERE "VUNSCP"."DASFM"='30-apr-10'
kkoqbc-subheap (delete addr=0x2a9746b058, in-use=11544, alloc=12408)
kkoqbc-end
: call(in-use=63208, alloc=81816), compile(in-use=41688, alloc=44568)
apadrv-end: call(in-use=63208, alloc=81816), compile(in-use=42872, alloc=44568)
sql_id=3xakq94fcx4td.
Current SQL statement for this session:
EXPLAIN PLAN FOR select * from VUNSCP where dasfm='30-apr-10'
============
Plan Table
============
---------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
---------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 191K | |
| 1 | VIEW | VUNSCP | 12M | 1529M | 191K | 00:39:11 |
| 2 | WINDOW SORT | | 12M | 646M | 191K | 00:39:11 |
| 3 | TABLE ACCESS FULL | SFMCPT | 12M | 646M | 27K | 00:06:36 |
---------------------------------------+-----------------------------------+
Predicate Information:
1 - filter("DASFM"='30-apr-10')Edited by: Ahmed AANGOUR on 5 mai 2010 08:43 -
CBO bug? Lack of SORT UNIQUE.
Hi all,
Let's consider following case:
create table tmp as select rownum id, 0 sign from dual connect by level <= 100;
create index tmp_i on tmp(id,sign);
create table t as
select mod(rownum,2) id, mod(rownum,3) val
from dual
connect by level <= 100000;
begin
dbms_stats.gather_table_stats (
user,
'T',
estimate_percent => null,
method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY',
cascade => true
end;
begin
dbms_stats.gather_table_stats (
user,
'TMP',
estimate_percent => null,
method_opt => 'FOR ALL COLUMNS SIZE SKEWONLY',
cascade => true
end;
/As you can see it scans TMP_I 50 000 times for statement with max (irrespective of distinct in subquery).
Is there any way to enforce CBO to make SORT UNIQUE for max as well as for count so that it scans TMP_I only 3 times?
SQL> select --+ leading(t) use_nl(t tmp)
2 max(id)
3 from tmp tmp
4 where tmp.sign = 0
5 and tmp.id in (select val from t where id = 1);
MAX(ID)
2
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.14 | 159 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.14 | 159 |
| 2 | NESTED LOOPS | | 1 | 49750 | 33333 |00:00:00.13 | 159 |
|* 3 | TABLE ACCESS FULL| T | 1 | 50000 | 50000 |00:00:00.02 | 156 |
|* 4 | INDEX RANGE SCAN | TMP_I | 50000 | 1 | 33333 |00:00:00.07 | 3 |
Predicate Information (identified by operation id):
3 - filter("ID"=1)
4 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)
SQL> select --+ leading(t) use_nl(t tmp)
2 max(id)
3 from tmp tmp
4 where tmp.sign = 0
5 and tmp.id in (select distinct val from t where id = 1);
MAX(ID)
2
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.14 | 159 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.14 | 159 |
| 2 | NESTED LOOPS | | 1 | 49750 | 33333 |00:00:00.13 | 159 |
|* 3 | TABLE ACCESS FULL| T | 1 | 50000 | 50000 |00:00:00.01 | 156 |
|* 4 | INDEX RANGE SCAN | TMP_I | 50000 | 1 | 33333 |00:00:00.07 | 3 |
Predicate Information (identified by operation id):
3 - filter("ID"=1)
4 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)
SQL> select --+ leading(t) use_nl(t tmp)
2 count(id)
3 from tmp tmp
4 where tmp.sign = 0
5 and tmp.id in (select val from t where id = 1);
COUNT(ID)
2
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.03 | 158 | | | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.03 | 158 | | | |
| 2 | NESTED LOOPS | | 1 | 3 | 2 |00:00:00.03 | 158 | | | |
| 3 | SORT UNIQUE | | 1 | 50000 | 3 |00:00:00.03 | 156 | 2048 | 2048 | 2048 (0)|
|* 4 | TABLE ACCESS FULL| T | 1 | 50000 | 50000 |00:00:00.01 | 156 | | | |
|* 5 | INDEX RANGE SCAN | TMP_I | 3 | 1 | 2 |00:00:00.01 | 2 | | | |
Predicate Information (identified by operation id):
4 - filter("ID"=1)
5 - access("TMP"."ID"="VAL" AND "TMP"."SIGN"=0)I can't figure out why SORT UNIQUE is absent for statement with max.
PS. 11gR2Thanks for reply.
user503699 wrote:
I don't think it is a good idea to compare your last and first query timings as they are 2 different queries.Ok. I could compare query with max(id), sign(count(*)+1) vs max(id), sign(1). They always produce the same results so can be considered as the same.
But I think that max(id), count(*) vs max(id) was enough to explain my point.
user503699 wrote:
If you are so sure of that you can write something like following :
SQL> with data as (select /*+ materialize */ distinct val as val from t where id = 1)
select max(id) from tmp tmp where tmp.sign = 0 and tmp.id in (select val from data) ; 2
I thought about that. I’m reluctant to use undocumented hints such as materialize. So folowing query has almost the best plan for my data:
with data as (select distinct val as val from t where id = 1 and rownum > 0)
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select * from data);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 8 | 50 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
| 2 | NESTED LOOPS | | 3 | 24 | 50 (8)| 00:00:01 |
| 3 | VIEW | | 3 | 9 | 50 (8)| 00:00:01 |
| 4 | HASH UNIQUE | | 3 | 18 | 50 (8)| 00:00:01 |
| 5 | COUNT | | | | | |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL| T | 50000 | 292K| 47 (3)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | TMP_I | 1 | 5 | 0 (0)| 00:00:01 |
Predicate Information (identified by operation id):
6 - filter(ROWNUM>0)
7 - filter("ID"=1)
8 - access("TMP"."ID"="DATA"."VAL" AND "TMP"."SIGN"=0) And changing two hidden parameters may lead to the same plan as I expect:
alter session set "_gby_hash_aggregation_enabled" = false;
alter session set "_simple_view_merging" = false;
with data as (select distinct val as val from t where id = 1)
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select * from data);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 18 | 50 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 18 | | |
| 2 | NESTED LOOPS | | 3 | 54 | 50 (8)| 00:00:01 |
| 3 | VIEW | | 3 | 39 | 50 (8)| 00:00:01 |
| 4 | SORT UNIQUE | | 3 | 18 | 50 (8)| 00:00:01 |
|* 5 | TABLE ACCESS FULL| T | 50000 | 292K| 47 (3)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | TMP_I | 1 | 5 | 0 (0)| 00:00:01 |
Predicate Information (identified by operation id):
5 - filter("ID"=1)
6 - access("TMP"."ID"="DATA"."VAL" AND "TMP"."SIGN"=0) But here I've got two additional questions:
1. no_use_hash_aggregation can be used instead of "alter session set "_gby_hash_aggregation_enabled" = false;"
What hint can be used instead of "alter session set "_simple_view_merging" = false;"?
2. Is there any way to enforce CBO to use for this one
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select distinct val as val from t where id = 1 and rownum > 0);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 5 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | FIRST ROW | | 1 | 5 | 1 (0)| 00:00:01 |
|* 3 | INDEX FULL SCAN (MIN/MAX)| TMP_I | 1 | 5 | 1 (0)| 00:00:01 |
|* 4 | FILTER | | | | | |
| 5 | COUNT | | | | | |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL | T | 2 | 12 | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------- the same plan as for this
with data as (select distinct val as val from t where id = 1 and rownum > 0)
select
max(id)
from tmp tmp
where tmp.sign = 0
and tmp.id in (select * from data);
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 8 | 50 (8)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
| 2 | NESTED LOOPS | | 3 | 24 | 50 (8)| 00:00:01 |
| 3 | VIEW | | 3 | 9 | 50 (8)| 00:00:01 |
| 4 | HASH UNIQUE | | 3 | 18 | 50 (8)| 00:00:01 |
| 5 | COUNT | | | | | |
|* 6 | FILTER | | | | | |
|* 7 | TABLE ACCESS FULL| T | 50000 | 292K| 47 (3)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | TMP_I | 1 | 5 | 0 (0)| 00:00:01 |
I don't have anything against subquery factoring clause. Just for personal interest.
(I have read topic "Thread: Materialize a Subquery without using "with" clause"
Materialize a Subquery without using "with" clause
user503699 wrote:
If you are not going to change other things (like stats collection method, table/index structures etc.) which allow optimizer to choose better plan and you know your data better, you may need to be very specific with the hints and also may have to use additional hints in order to influence optimizer decisions.
One way to do that would be to get the base details from oracle as follows (and tweak them) :I didn't find keyword "ADVANCED" in specification for DISPLAY_CURSOR Function in documentation. Nice trick.
But anyway outline data makes sense only in case when query already has desirable execution plan. -
Subquery conditional execution using cbo
hellou
how i do for execute a subquery conditionally, using the cbo??
i got an example:
create table table1 AS
SELECT * FROM (
SELECT 1 id, 'a' boss FROM dual
union all
SELECT 3 id, 'b' boss FROM dual
union all
SELECT 5 id, 'a' boss FROM dual
union all
SELECT 7 id, 'b' boss FROM dual
union all
SELECT 9 id, 'a' boss FROM dual
create index idx_table1 on table1(boss, id)
create table table2 AS
SELECT * FROM (
SELECT 2 id, 'b' boss FROM dual
union all
SELECT 4 id, 'a' boss FROM dual
union all
SELECT 6 id, 'b' boss FROM dual
union all
SELECT 8 id, 'a' boss FROM dual
union all
SELECT 10 id, 'b' boss FROM dual
create index idx_table2 on table2(boss, id)
CREATE OR REPLACE FUNCTION print_hi
isb in varchar2
return number
IS
BEGIN
dbms_output.put_Line(isb);
return 0;
END;
-- the query !!!!!!!
with data AS
SELECT
FROM (
-- subquery #1
SELECT
1 query_name,
id pibot,
boss
FROM table1
WHERE print_hi(id) = 0
union all
-- subquery #2
SELECT
2 query_name,
id pibot,
boss
FROM table2
SELECT
pibot + query_name / 10 pibot
FROM data
WHERE 1 = 1
AND boss = :boss
AND (
query_name = :q
AND pibot > :p
OR query_name > :q )
AND rownum <= 3i want than only the query #2 be executed.
the query #1 print data in the screen when is executed (for the function print_hi).
now i execute the query with the variables data as:
boss = 'a'
q = 2
p = 0
when i execute the query using rules, then not print anything in the screen.
when i execute the query using costs, then print 1 5 9 in the screen. this means than the query #1 is being executed when this should not
help .. tx
SELECT * FROM v$version
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - Prod
PL/SQL Release 10.2.0.5.0 - Production
CORE10.2.0.5.0Production
TNS for Linux: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - ProductionAs often is, the predicates section of the execution plan is quite revealing on this one.
Take your original query
explain plan for
with data AS
(SELECT *
FROM (-- subquery #1
SELECT 1 query_name,id pibot,boss
FROM table1
WHERE print_hi(id) = 0
union all
-- subquery #2
SELECT 2 query_name,id pibot,boss
FROM table2))
SELECT pibot + query_name / 10 pibot
FROM data
WHERE 1 = 1
AND boss = :boss
AND (query_name = :q
AND pibot > :p
OR query_name > :q )
AND rownum <= 3;
select * from table(dbms_xplan.display);gives
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 2 | 38 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 2 | 38 | 2 (0)| 00:00:01 |
| 3 | UNION-ALL | | | | | |
|* 4 | INDEX RANGE SCAN| IDX_TABLE1 | 1 | 16 | 1 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN| IDX_TABLE2 | 1 | 16 | 1 (0)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter(ROWNUM<=3)
4 - access("BOSS"=:BOSS)
filter("PRINT_HI"(TO_CHAR("ID"))=0 AND (1>TO_NUMBER(:Q) OR
1=TO_NUMBER(:Q) AND "ID">TO_NUMBER(:P)))
5 - access("BOSS"=:BOSS)
filter(2>TO_NUMBER(:Q) OR 2=TO_NUMBER(:Q) AND "ID">TO_NUMBER(:P))Assuming that the FILTER logic in STEP 4 is followed to order, it's not then possible with this query as is to short-circuit the evaluation of PRINT_HI as it is evaluated first.
When you make a change (just to q not necessarily to boss as well)
from
query_name = :qto
query_name = 2You'll hopefully notice the difference in predicate evaluation with the extra filter step:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 2 | 38 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | VIEW | | 2 | 38 | 2 (0)| 00:00:01 |
| 3 | VIEW | | 2 | 38 | 2 (0)| 00:00:01 |
| 4 | UNION-ALL | | | | | |
|* 5 | FILTER | | | | | |
|* 6 | INDEX RANGE SCAN| IDX_TABLE1 | 1 | 16 | 1 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | IDX_TABLE2 | 1 | 16 | 1 (0)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter(ROWNUM<=3)
5 - filter(1>TO_NUMBER(:Q))
6 - access("BOSS"=:BOSS)
filter("PRINT_HI"(TO_CHAR("ID"))=0)
7 - access("BOSS"=:BOSS)
filter("ID">TO_NUMBER(:P) OR 2>TO_NUMBER(:Q)) -
Hello,
Some days back, I came across a blog entry in which author concluded that when a = b and b = c, oracle does not conclude as a = c. He also provided a test case to prove his point. The URL is [http://sandeepredkar.blogspot.com/2009/09/query-performance-join-conditions.html]
Now, I thought that that can not be true. So I executed his test case (on 10.2.04) and the outcome indeed proved his point. Initially, I thought it might be due to absense of PK-FK relationship. But even after adding the PK-FK relationship, there was no change in the outcome. Although, when I modified the subquery with list of values, both the queries performed equally. I tried asking the author on his blog but it seems he has not yet seen my comment.
I am pasting his test case below. Can somebody please help me understand why CBO does not/can not use optimal plan here?
SQL> create table cu_all (custid number, addr varchar2(200), ph number, cano number, acctype varchar2(10));
Table created.
SQL> create table ca_receipt (custid number, caamt number, cadt date, totbal number);
Table created.
SQL>
SQL> insert into cu_all
2 select lvl,
3 dbms_random.string('A',30),
4 round(dbms_random.value(1,100000)),
5 round(dbms_random.value(1,10000)),
6 dbms_random.string('A',10)
7 from (select level "LVL" from dual connect by level <=200000);
200000 rows created.
SQL> insert into ca_receipt
2 select round(dbms_random.value(1,10000)),
3 round(dbms_random.value(1,100000)),
4 sysdate - round(dbms_random.value(1,100000)),
5 round(dbms_random.value(1,100000))
6 from (select level "LVL" from dual connect by level <=500000);
500000 rows created.
SQL> create unique index pk_cu_all_ind on cu_all(custid);
Index created.
SQL> create index ind2_cu_all on cu_all(CANO);
Index created.
SQL> create index ind_ca_receipt_custid on ca_receipt(custid);
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'CU_ALL', cascade=>true);
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user,'CA_RECEIPT', cascade=>true);
PL/SQL procedure successfully completed.
Now let us execute the query with trace on. This is the similar query which was provided to me.
SQL> set autot trace
SQL> SELECT ca.*, cu.*
2 FROM ca_receipt CA,
3 cu_all CU
4 WHERE CA.CUSTID = CU.CUSTID
5 AND CA.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
6 CONNECT BY PRIOR CUSTID = CANO)
7 ORDER BY ACCTYPE DESC;
289 rows selected.
Execution Plan
Plan hash value: 3186098611
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1000 | 81000 | 504 (2)| 00:00:07 |
| 1 | SORT ORDER BY | | 1000 | 81000 | 504 (2)| 00:00:07 |
|* 2 | HASH JOIN | | 1000 | 81000 | 503 (2)| 00:00:07 |
| 3 | NESTED LOOPS | | | | | |
| 4 | NESTED LOOPS | | 1000 | 26000 | 112 (1)| 00:00:02 |
| 5 | VIEW | VW_NSO_1 | 20 | 100 | 21 (0)| 00:00:01 |
| 6 | HASH UNIQUE | | 20 | 180 | | |
|* 7 | CONNECT BY WITH FILTERING | | | | | |
| 8 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 9 | 2 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | | | | |
| 11 | CONNECT BY PUMP | | | | | |
| 12 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 21 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
| 16 | TABLE ACCESS FULL | CU_ALL | 200K| 10M| 389 (1)| 00:00:05 |
Predicate Information (identified by operation id):
2 - access("CA"."CUSTID"="CU"."CUSTID")
7 - access("CANO"=PRIOR "CUSTID")
9 - access("CUSTID"=2353)
13 - access("CANO"=PRIOR "CUSTID")
14 - access("CA"."CUSTID"="CUSTID")
Statistics
1 recursive calls
0 db block gets
2249 consistent gets
25 physical reads
0 redo size
11748 bytes sent via SQL*Net to client
729 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
7 sorts (memory)
0 sorts (disk)
289 rows processed
If you look at the query, it seems to be normal one.
But the problem is here-
Query is having two tables CA and CU. From the inner CU table query, it fetches records and joins with CA table an CA table Joins with CU table using the same column.
Here the inner query joins with CA table and cardinality of the query gets changed. So it is opting FTS when joining to CU table again.
This is causing the performance bottleneck. So to resolve the issue, I have change the joining condition.
Now if we check, following is the proper execution plan. Also the consistents gets have been reduced to 797 against 2249 in original query.
SQL> SELECT ca.*, cu.*
2 FROM ca_receipt CA,
3 cu_all CU
4 WHERE CA.CUSTID = CU.CUSTID
5 AND CU.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
6 CONNECT BY PRIOR CUSTID = CANO)
7 ORDER BY ACCTYPE DESC;
289 rows selected.
Execution Plan
Plan hash value: 3713271440
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1000 | 81000 | 133 (2)| 00:00:02 |
| 1 | SORT ORDER BY | | 1000 | 81000 | 133 (2)| 00:00:02 |
| 2 | NESTED LOOPS | | | | | |
| 3 | NESTED LOOPS | | 1000 | 81000 | 132 (1)| 00:00:02 |
| 4 | NESTED LOOPS | | 20 | 1200 | 42 (3)| 00:00:01 |
| 5 | VIEW | VW_NSO_1 | 20 | 100 | 21 (0)| 00:00:01 |
| 6 | HASH UNIQUE | | 20 | 180 | | |
|* 7 | CONNECT BY WITH FILTERING | | | | | |
| 8 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 9 | 2 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | | | | |
| 11 | CONNECT BY PUMP | | | | | |
| 12 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 21 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
| 14 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 55 | 1 (0)| 00:00:01 |
|* 15 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 0 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
| 17 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
Predicate Information (identified by operation id):
7 - access("CANO"=PRIOR "CUSTID")
9 - access("CUSTID"=2353)
13 - access("CANO"=PRIOR "CUSTID")
15 - access("CU"."CUSTID"="CUSTID")
16 - access("CA"."CUSTID"="CU"."CUSTID")
Statistics
1 recursive calls
0 db block gets
797 consistent gets
1 physical reads
0 redo size
11748 bytes sent via SQL*Net to client
729 bytes received via SQL*Net from client
21 SQL*Net roundtrips to/from client
7 sorts (memory)
0 sorts (disk)
289 rows processeduser503699 wrote:
Hello,
Some days back, I came across a blog entry in which author concluded that when a = b and b = c, oracle does not conclude as a = c. He also provided a test case to prove his point. The URL is [http://sandeepredkar.blogspot.com/2009/09/query-performance-join-conditions.html]
Now, I thought that that can not be true. So I executed his test case (on 10.2.04) and the outcome indeed proved his point. Initially, I thought it might be due to absense of PK-FK relationship. But even after adding the PK-FK relationship, there was no change in the outcome. Although, when I modified the subquery with list of values, both the queries performed equally. I tried asking the author on his blog but it seems he has not yet seen my comment.I see that Jonathan provided a helpful reply to you while I was in the process of setting up a test case.
Is it possible that the optimizer is correct? What if... the optimizer transformed the SQL statement? What if... the original SQL statement actually executes faster than the modified SQL statement? What if... the autotrace plans do not match the plans shown on that web page?
The first execution with the original SQL statement:
ALTER SESSION SET EVENTS '10053 trace name context forever, level 1';
ALTER SESSION SET TRACEFILE_IDENTIFIER = 'test_case';
SET AUTOTRACE TRACE
SELECT ca.*, cu.*
FROM ca_receipt CA,
cu_all CU
WHERE CA.CUSTID = CU.CUSTID
AND CA.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
CONNECT BY PRIOR CUSTID = CANO)
ORDER BY ACCTYPE DESC;
Execution Plan
Plan hash value: 2794552689
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1001 | 81081 | 1125 (2)| 00:00:01 |
| 1 | SORT ORDER BY | | 1001 | 81081 | 1125 (2)| 00:00:01 |
| 2 | NESTED LOOPS | | 1001 | 81081 | 1123 (1)| 00:00:01 |
| 3 | NESTED LOOPS | | 1001 | 26026 | 114 (2)| 00:00:01 |
| 4 | VIEW | VW_NSO_1 | 20 | 100 | 22 (0)| 00:00:01 |
| 5 | HASH UNIQUE | | 20 | 180 | | |
|* 6 | CONNECT BY WITH FILTERING | | | | | |
| 7 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 19 | 2 (0)| 00:00:01 |
|* 8 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 9 | NESTED LOOPS | | | | | |
| 10 | CONNECT BY PUMP | | | | | |
| 11 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 22 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
| 15 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 55 | 1 (0)| 00:00:01 |
|* 16 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 0 (0)| 00:00:01 |
Predicate Information (identified by operation id):
6 - access("CANO"=PRIOR "CUSTID")
8 - access("CUSTID"=2353)
12 - access("CANO"=PRIOR "CUSTID")
14 - access("CA"."CUSTID"="$nso_col_1")
16 - access("CA"."CUSTID"="CU"."CUSTID")
Statistics
1 recursive calls
0 db block gets
232 consistent gets
7 physical reads
0 redo size
2302 bytes sent via SQL*Net to client
379 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processedThe second SQL statement which was modified:
ALTER SESSION SET TRACEFILE_IDENTIFIER = 'test_case2';
SELECT ca.*, cu.*
FROM ca_receipt CA,
cu_all CU
WHERE CA.CUSTID = CU.CUSTID
AND CU.CUSTID IN (SELECT CUSTID FROM cu_all START WITH custid = 2353
CONNECT BY PRIOR CUSTID = CANO)
ORDER BY ACCTYPE DESC;
Execution Plan
Plan hash value: 497148844
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1001 | 81081 | 136 (3)| 00:00:01 |
| 1 | SORT ORDER BY | | 1001 | 81081 | 136 (3)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID | CA_RECEIPT | 50 | 1050 | 52 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 1001 | 81081 | 134 (2)| 00:00:01 |
| 4 | NESTED LOOPS | | 20 | 1200 | 43 (3)| 00:00:01 |
| 5 | VIEW | VW_NSO_1 | 20 | 100 | 22 (0)| 00:00:01 |
| 6 | HASH UNIQUE | | 20 | 180 | | |
|* 7 | CONNECT BY WITH FILTERING | | | | | |
| 8 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 19 | 2 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 1 (0)| 00:00:01 |
| 10 | NESTED LOOPS | | | | | |
| 11 | CONNECT BY PUMP | | | | | |
| 12 | TABLE ACCESS BY INDEX ROWID| CU_ALL | 20 | 180 | 22 (0)| 00:00:01 |
|* 13 | INDEX RANGE SCAN | IND2_CU_ALL | 20 | | 1 (0)| 00:00:01 |
| 14 | TABLE ACCESS BY INDEX ROWID | CU_ALL | 1 | 55 | 1 (0)| 00:00:01 |
|* 15 | INDEX UNIQUE SCAN | PK_CU_ALL_IND | 1 | | 0 (0)| 00:00:01 |
|* 16 | INDEX RANGE SCAN | IND_CA_RECEIPT_CUSTID | 50 | | 2 (0)| 00:00:01 |
Predicate Information (identified by operation id):
7 - access("CANO"=PRIOR "CUSTID")
9 - access("CUSTID"=2353)
13 - access("CANO"=PRIOR "CUSTID")
15 - access("CU"."CUSTID"="$nso_col_1")
16 - access("CA"."CUSTID"="CU"."CUSTID")
Statistics
1 recursive calls
0 db block gets
162 consistent gets
0 physical reads
0 redo size
2302 bytes sent via SQL*Net to client
379 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processed
ALTER SESSION SET EVENTS '10053 trace name context off';The question might be asked, does the final SQL statement actually executed look the same as the original? Slightly reformatted:
The first SQL statement:
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CA.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;
Final Transformation:
SELECT
"CA"."CUSTID" "CUSTID",
"CA"."CAAMT" "CAAMT",
"CA"."CADT" "CADT",
"CA"."TOTBAL" "TOTBAL",
"CU"."CUSTID" "CUSTID",
"CU"."ADDR" "ADDR",
"CU"."PH" "PH",
"CU"."CANO" "CANO",
"CU"."ACCTYPE" "ACCTYPE"
FROM
(SELECT DISTINCT
"CU_ALL"."CUSTID" "$nso_col_1"
FROM
"TESTUSER"."CU_ALL" "CU_ALL"
WHERE
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID"
CONNECT BY
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID") "VW_NSO_1",
"TESTUSER"."CA_RECEIPT" "CA",
"TESTUSER"."CU_ALL" "CU"
WHERE
"CA"."CUSTID"="VW_NSO_1"."$nso_col_1"
AND "CA"."CUSTID"="CU"."CUSTID"
ORDER BY
"CU"."ACCTYPE" DESC;The second SQL statement:
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CU.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;
Final Transformation:
SELECT
"CA"."CUSTID" "CUSTID",
"CA"."CAAMT" "CAAMT",
"CA"."CADT" "CADT",
"CA"."TOTBAL" "TOTBAL",
"CU"."CUSTID" "CUSTID",
"CU"."ADDR" "ADDR",
"CU"."PH" "PH",
"CU"."CANO" "CANO",
"CU"."ACCTYPE" "ACCTYPE"
FROM
(SELECT DISTINCT
"CU_ALL"."CUSTID" "$nso_col_1"
FROM
"TESTUSER"."CU_ALL" "CU_ALL"
WHERE
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID"
CONNECT BY
"CU_ALL"."CANO"=PRIOR "CU_ALL"."CUSTID") "VW_NSO_1",
"TESTUSER"."CA_RECEIPT" "CA",
"TESTUSER"."CU_ALL" "CU"
WHERE
"CA"."CUSTID"="CU"."CUSTID"
AND "CU"."CUSTID"="VW_NSO_1"."$nso_col_1"
ORDER BY
"CU"."ACCTYPE" DESC;Now, let's take a look at performance, flushing the buffer cache to force physical reads:
SET AUTOTRACE OFF
SET TIMING ON
SET AUTOTRACE TRACEONLY STATISTICS
SET ARRAYSIZE 100
ALTER SYSTEM FLUSH BUFFER_CACHE;
ALTER SYSTEM FLUSH BUFFER_CACHE;
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CA.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;
ALTER SYSTEM FLUSH BUFFER_CACHE;
ALTER SYSTEM FLUSH BUFFER_CACHE;
SELECT
CA.*,
CU.*
FROM
CA_RECEIPT CA,
CU_ALL CU
WHERE
CA.CUSTID = CU.CUSTID
AND CU.CUSTID IN (
SELECT
CUSTID
FROM
CU_ALL
START WITH
CUSTID = 2353
CONNECT BY PRIOR
CUSTID = CANO)
ORDER BY
ACCTYPE DESC;The output:
/* (with AND CA.CUSTID IN...) */
52 rows selected.
Elapsed: 00:00:00.64
Statistics
0 recursive calls
0 db block gets
232 consistent gets
592 physical reads
0 redo size
2044 bytes sent via SQL*Net to client
346 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processed
/* (with AND CU.CUSTID IN...) */
52 rows selected.
Elapsed: 00:00:00.70
Statistics
0 recursive calls
0 db block gets
162 consistent gets
712 physical reads
0 redo size
2044 bytes sent via SQL*Net to client
346 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
52 rows processedThe original SQL statement completed in 0.64 seconds, and the second completed in 0.70 seconds.
Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc. -
CBO refuses hint (sometimes)
Sometimes, the CBO does not take hints. Can anyone explain it?
SQL:
SELECT * FROM v_osi_child v1 WHERE mainuuid IN (SELECT uuid FROM ot_sys_index_org v2 WHERE mainuuid IN(:p1))v_osi_child is a view which union-alls about 50 tables. ot_sys_index_org is here only used for getting some mainuuids.
The statement itself is free of sense :)
Explain plan:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 4 | 17252 | 402K (1)| 01:20:31 |
|* 1 | HASH JOIN | | 4 | 17252 | 402K (1)| 01:20:31 |
|* 2 | INDEX RANGE SCAN | PK_OTSYSINDEX | 4 | 340 | 4 (0)| 00:00:01 |
| 3 | VIEW | V_OSI_CHILD | 56M| 223G| 402K (1)| 01:20:27 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS FULL| FL_ALLG_BENUTZERDATEN | 16797 | 1295K| 105 (0)| 00:00:02 |
| 6 | TABLE ACCESS FULL| FL_BERATUNG | 17 | 1343 | 3 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL| PA_KBIVBI | 16797 | 1295K| 105 (0)| 00:00:02 |
...This statement needs more than 10 minutes.
Inserting a hint:
SELECT /*+ push_pred(v1) */ * FROM v_osi_child v1 WHERE mainuuid IN (SELECT uuid FROM ot_sys_index_org v2 WHERE mainuuid IN(:p1));Explain plan:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 4 | 17852 | 12747 (1)| 00:02:33 |
| 1 | NESTED LOOPS | | 4 | 17852 | 12747 (1)| 00:02:33 |
|* 2 | INDEX RANGE SCAN | PK_OTSYSINDEX | 4 | 532 | 4 (0)| 00:00:01 |
| 3 | VIEW | V_OSI_CHILD | 1 | 4330 | 3186 (1)| 00:00:39 |
| 4 | UNION ALL PUSHED PREDICATE | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| FL_ALLG_BENUTZERDATEN | 1 | 79 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | OSI_FLALLGBENUTZE_MAINUUID | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| FL_BERATUNG | 1 | 79 | 2 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | OSI_FLBERATUNG_MAINUUID | 1 | | 1 (0)| 00:00:01 |
| 9 | TABLE ACCESS BY INDEX ROWID| PA_KBIVBI | 1 | 79 | 2 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | OSI_PAKBIVBI_MAINUUID | 1 | | 1 (0)| 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID| FL_K_AKTIVITAET | 1 | 100 | 2 (0)| 00:00:01 |
|* 12 | INDEX RANGE SCAN | OSI_FLKAKTIVITAET_MAINUUID | 1 | | 1 (0)| 00:00:01 |
...Well, using the index on mainuuids is realy a good idea, if the estimated resultset of the subquery are about 4 rows.
Costs are decreased from 402k to 12747.
Query runs in a second.
Now, lets modify the subquery a little bit. Again, the estimated result of the subquery are 4 rows:
SELECT * FROM v_osi_child v1 WHERE mainuuid IN (SELECT mainuuid FROM ot_sys_index_org v2 WHERE value IN(:p1));Explain plan:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 4 | 17104 | 402K (1)| 01:20:31 |
|* 1 | HASH JOIN RIGHT SEMI| | 4 | 17104 | 402K (1)| 01:20:31 |
|* 2 | INDEX RANGE SCAN | IX_OT_SYS_INDEX01 | 4 | 192 | 5 (0)| 00:00:01 |
| 3 | VIEW | V_OSI_CHILD | 56M| 223G| 402K (1)| 01:20:27 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS FULL| FL_ALLG_BENUTZERDATEN | 16797 | 1295K| 105 (0)| 00:00:02 |
| 6 | TABLE ACCESS FULL| FL_BERATUNG | 17 | 1343 | 3 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL| PA_KBIVBI | 16797 | 1295K| 105 (0)| 00:00:02 |
| 8 | TABLE ACCESS FULL| FL_K_AKTIVITAET | 26 | 2600 | 3 (0)| 00:00:01 |
...Well, almost the same values...
Now, use the same hint:
SELECT /*+ push_pred(v1) */ * FROM v_osi_child v1 WHERE mainuuid IN (SELECT mainuuid FROM ot_sys_index_org v2 WHERE value IN(:p1));Explain plan:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 4 | 17104 | 402K (1)| 01:20:31 |
|* 1 | HASH JOIN RIGHT SEMI| | 4 | 17104 | 402K (1)| 01:20:31 |
|* 2 | INDEX RANGE SCAN | IX_OT_SYS_INDEX01 | 4 | 192 | 5 (0)| 00:00:01 |
| 3 | VIEW | V_OSI_CHILD | 56M| 223G| 402K (1)| 01:20:27 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS FULL| FL_ALLG_BENUTZERDATEN | 16797 | 1295K| 105 (0)| 00:00:02 |
| 6 | TABLE ACCESS FULL| FL_BERATUNG | 17 | 1343 | 3 (0)| 00:00:01 |
| 7 | TABLE ACCESS FULL| PA_KBIVBI | 16797 | 1295K| 105 (0)| 00:00:02 |
...Nothing has changed.
I can't explain it. It seems to be an oracle-bug...
Release: 11.1.0.7.0 - 64bit Production
OS: RHEL 5.3Ulrich Weiss wrote:
All this is readable from the explain plans.I don't know the reason behind this behaviour and I don't have a 11g version to test on, but I found similar observations on a 10g database. A small yet complete reproducible test case always helps. Here is mine:
SQL> select * from v$version ;
BANNER
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for Solaris: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production
SQL> drop view v_t ;
View dropped.
SQL> drop table t1 purge ;
Table dropped.
SQL> drop table t purge ;
Table dropped.
SQL> create table t nologging as select * from all_objects ;
Table created.
SQL> create table t1 nologging as select * from t where rownum <= 1000 ;
Table created.
SQL> create or replace view v_t as
2 select * from t where object_type = 'PACKAGE'
3 union all
4 select * from t where object_type = 'PACKAGE BODY' ;
View created.
SQL> explain plan for select * from v_t where object_id in (select object_id from t1 where owner = '
2 SYS') ;
Explained.
SQL> exec dbms_stats.gather_table_stats(user, 'T') ;
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats(user, 'T1') ;
PL/SQL procedure successfully completed.
SQL> explain plan for select * from v_t where object_id in (select object_id from t1 where owner = 'SYS') ;
Explained.
SQL> select * from table(dbms_xplan.display) ;
PLAN_TABLE_OUTPUT
Plan hash value: 443534535
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 2 | 274 | 333 (2)| 00:00:04 |
|* 1 | HASH JOIN RIGHT SEMI| | 2 | 274 | 333 (2)| 00:00:04 |
|* 2 | TABLE ACCESS FULL | T1 | 893 | 8037 | 5 (0)| 00:00:01 |
| 3 | VIEW | V_T | 2055 | 256K| 327 (2)| 00:00:04 |
| 4 | UNION-ALL | | | | | |
|* 5 | TABLE ACCESS FULL| T | 1067 | 97K| 164 (2)| 00:00:02 |
|* 6 | TABLE ACCESS FULL| T | 988 | 92872 | 164 (2)| 00:00:02 |
Predicate Information (identified by operation id):
1 - access("OBJECT_ID"="OBJECT_ID")
2 - filter("OWNER"='SYS')
5 - filter("OBJECT_TYPE"='PACKAGE')
6 - filter("OBJECT_TYPE"='PACKAGE BODY')
21 rows selected.
SQL> explain plan for select /*+ push_pred(v_t) */ * from v_t where object_id in (select object_id from t1 where owner = 'SYS') ;
Explained.
SQL> select * from table(dbms_xplan.display) ;
PLAN_TABLE_OUTPUT
Plan hash value: 443534535
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 2 | 274 | 333 (2)| 00:00:04 |
|* 1 | HASH JOIN RIGHT SEMI| | 2 | 274 | 333 (2)| 00:00:04 |
|* 2 | TABLE ACCESS FULL | T1 | 893 | 8037 | 5 (0)| 00:00:01 |
| 3 | VIEW | V_T | 2055 | 256K| 327 (2)| 00:00:04 |
| 4 | UNION-ALL | | | | | |
|* 5 | TABLE ACCESS FULL| T | 1067 | 97K| 164 (2)| 00:00:02 |
|* 6 | TABLE ACCESS FULL| T | 988 | 92872 | 164 (2)| 00:00:02 |
Predicate Information (identified by operation id):
1 - access("OBJECT_ID"="OBJECT_ID")
2 - filter("OWNER"='SYS')
5 - filter("OBJECT_TYPE"='PACKAGE')
6 - filter("OBJECT_TYPE"='PACKAGE BODY')
21 rows selected.
SQL> explain plan for select v_t.* from v_t, t1 where v_t.object_id = t1.object_id and t1.owner = 'SYS' ;
Explained.
SQL> select * from table(dbms_xplan.display) ;
PLAN_TABLE_OUTPUT
Plan hash value: 2725479221
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1834 | 245K| 333 (2)| 00:00:04 |
|* 1 | HASH JOIN | | 1834 | 245K| 333 (2)| 00:00:04 |
|* 2 | TABLE ACCESS FULL | T1 | 893 | 8037 | 5 (0)| 00:00:01 |
| 3 | VIEW | V_T | 2055 | 256K| 327 (2)| 00:00:04 |
| 4 | UNION-ALL | | | | | |
|* 5 | TABLE ACCESS FULL| T | 1067 | 97K| 164 (2)| 00:00:02 |
|* 6 | TABLE ACCESS FULL| T | 988 | 92872 | 164 (2)| 00:00:02 |
Predicate Information (identified by operation id):
1 - access("V_T"."OBJECT_ID"="T1"."OBJECT_ID")
2 - filter("T1"."OWNER"='SYS')
5 - filter("OBJECT_TYPE"='PACKAGE')
6 - filter("OBJECT_TYPE"='PACKAGE BODY')
21 rows selected.
SQL> explain plan for select /*+ push_pred(v_t) */ v_t.* from v_t, t1 where v_t.object_id = t1.object_id and t1.owner = 'SYS' ;
Explained.
SQL> select * from table(dbms_xplan.display) ;
PLAN_TABLE_OUTPUT
Plan hash value: 3926093524
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1834 | 263K| 292K (2)| 00:58:28 |
| 1 | NESTED LOOPS | | 1834 | 263K| 292K (2)| 00:58:28 |
|* 2 | TABLE ACCESS FULL | T1 | 893 | 11609 | 5 (0)| 00:00:01 |
| 3 | VIEW | V_T | 1 | 134 | 327 (2)| 00:00:04 |
| 4 | UNION ALL PUSHED PREDICATE | | | | | |
|* 5 | TABLE ACCESS FULL | T | 1 | 94 | 164 (2)| 00:00:02 |
|* 6 | TABLE ACCESS FULL | T | 1 | 94 | 164 (2)| 00:00:02 |
Predicate Information (identified by operation id):
2 - filter("T1"."OWNER"='SYS')
5 - filter("OBJECT_ID"="T1"."OBJECT_ID" AND "OBJECT_TYPE"='PACKAGE')
6 - filter("OBJECT_ID"="T1"."OBJECT_ID" AND "OBJECT_TYPE"='PACKAGE BODY')
20 rows selected.As you can see, the PUSH_PRED hint is ignored when I use the IN clause with subquery.
I believe this is same as what you are experiencing. However, when I change the sql to use
a JOIN (instead of subquery), the hint is not ignored.
p.s. I hope my JOIN query is semantically equivalent to IN..SUBQUERY. -
CBO calculates un acceptable cost while using index.
Hi,
I was wondering to see the execution plan for both the case using index/without index.
We are using oracle 10G(10.2.0.3.0) with RAC in production at O/S:- sun solaris 10.
Java based application is running in this database. One of the sql query is taking long time to fetch the records. I analyzed the sql plan and noticed the FTS. I created indexes to the column(s) which is refering in where clauses. I noticed a strage behavior. Execution plan shows that the CBO is using right path but its not acceptable as application is time outs while return the rows.
first execution plan with/without index (not using the index).
PLAN_TABLE_OUTPUT
Plan hash value: 419342726
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 196 | 3332 | 67845 (3)| 00:13:35 |
|* 1 | TABLE ACCESS FULL | CWDBENUMDESCRIPTIONS | 1 | 35 | 3 (0)| 00:00:01 |
| 2 | SORT GROUP BY | | 196 | 3332 | 67845 (3)| 00:13:35 |
|* 3 | TABLE ACCESS FULL| CWORDERINSTANCE | 51466 | 854K| 67837 (3)| 00:13:35 |
Predicate Information (identified by operation id):
1 - filter("ERR"."CODE"=:B1)
3 - filter("OI"."ERROR_CODE" IS NOT NULL AND "OI"."DIVISION"='OR9' AND
"OI"."ACTIVE"=TO_NUMBER(:1) AND "OI"."ORDER_STATE"<>'O_NR_NS' AND
"OI"."ORDER_STATE"<>'C_C_QR' AND "OI"."ORDER_STATE"<>'O_NR_NS_D')
SQl query was modified to force the index to use /*+ index(oi oi_div) */ the execution is as below:-
PLAN_TABLE_OUTPUT
Plan hash value: 1157277132
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 196 | 3332 | 394K (1)| 01:18:52 |
|* 1 | TABLE ACCESS FULL | CWDBENUMDESCRIPTIONS | 1 | 35 | 3 (0)| 00:00:01 |
| 2 | SORT GROUP BY | | 196 | 3332 | 394K (1)| 01:18:52 |
|* 3 | TABLE ACCESS BY INDEX ROWID| CWORDERINSTANCE | 51466 | 854K| 394K (1)| 01:18:52 |
|* 4 | INDEX RANGE SCAN | OI_DIV | 3025K| | 14226 (1)| 00:02:51 |
Predicate Information (identified by operation id):
1 - filter("ERR"."CODE"=:B1)
3 - filter("OI"."ERROR_CODE" IS NOT NULL AND "OI"."ACTIVE"=TO_NUMBER(:1) AND
"OI"."ORDER_STATE"<>'O_NR_NS' AND "OI"."ORDER_STATE"<>'C_C_QR' AND
"OI"."ORDER_STATE"<>'O_NR_NS_D')
My questions are here:-
1). why FTS is less costly comparing index scan where there are 15000000 rows in the table.
2). while forcing index to use cost increase drastically (the statistics is latest one analyzed on 6th of feb 2009)
3). what should i suppose to change to get the performance benefit.
Thanks,
Pradeepuser587112 wrote:
select null, oi.division, oi.METADATATYPE, oi.ERROR_CODE,
( select err.DESCRIPTION
FROM CWDBENUMDESCRIPTIONS err
WHERE oi.ERROR_CODE = err.CODE
count(*)
from CWORDERINSTANCE oi
where
oi.ERROR_CODE is not null
and oi.division in ('BK9')
and oi.order_state not in ('O_NR_NS_D', 'C_C_QR', 'O_NR_NS')
and oi.metadatatype = :1
and oi.duedate>=:2
and oi.active = :3
group by oi.division, oi.metadatatype, oi.error_code
order by oi.division, oi.metadatatype, oi.error_code
In this query, if we use as it is how its being displayed, it runs like a rocket, but if we change division in ('OR9') instead of 'BK9' it does not use index and leads to time out the application.
Number of records division
1964690 ---------------- why this field is null ?
3090666 OR9
3468 BA9
1242 EL9
2702 IN9
258 EU9
196198 DT9
1268 PA9
8 BK9
2332 BH9
1405009 TP9
According to the stats in your original execution plan, it looks like you have a histogram on this column, and the index you want to use is on just the division column.
Oracle estimate for 'OR9' is 3M rowids from the index, resulting in 50,000+ rows from the table - that's a lot of work - it's not surprising that the optimizer chose a tablescan for 'OR9' - but chose to use the index for 'BK9' which has only 8 rows.
How often do you want to run this query ? And how accurate does the answer have to be ?
If you want this query to run faster even when it's processing a huge number of rows, one option would be to create a materialized view over the data that could supply the result set much more efficiently (possibly getting your front-end code to call a materialized view refresh before running the query).
The only other altenative is probably to create an index that covers all the columns in the query so that you don't have to visit the table - and if you order them correctly you won't have to do a sort group by. I think this index should do the trick: (division, metadatatype, error_code,active, duedate,orderstate). You could also compress this index on at least the first column, but possibly on far more columns, to minimise the size,
Regards
Jonathan Lewis
http://jonathanlewis.wordpress.com
http://www.jlcomp.demon.co.uk
"The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge."
Stephen Hawking
To post code, statspack/AWR report, execution plans or trace files, start and end the section with the tag {noformat}{noformat} (lowercase, curly brackets, no spaces) so that the text appears in fixed format. -
Hi,
Below is the view used in cursor with order by clause. Its taking lot of time for teching rows.
Could anyone help to tune this view. so that performace can be improved.
If I remove rule based optimzer hint and checked explain plan for CBO. Its doing many full table scans and also its kaing more time then rule based.
CREATE OR REPLACE VIEW V_FIF AS
SELECT /*+ rule */
ml_level_type fif_ml,
ifs.if_ml_id fif_ml_id,
ifs.if_id fif_if_id,
ifs.if_type fif_if_type,
ifs.if_min_stock_level fif_min_stock_level,
ifs.if_max_stock_level fif_max_stock_level,
ifs.if_mi_id fif_mi_id,
ifs.if_std_produced_qty fif_if_std_produced_qty,
ifs.if_lotsize fif_if_lotsize,
ifs.if_successor_qty fif_successor_qty,
ifs.if_successor_base_qty fif_successor_base_qty,
ifs.if_successor_uom fif_successor_uom,
ifs.if_if_id fif_if_if_id,
ifs.if_valid_flag fif_valid_flag,
ifs.if_freeze_fence fif_freeze_fence,
ifs.if_freeze_fence_date fif_freeze_fence_date,
ifs.if_freeze_fence_date_old fif_freeze_fence_date_old,
ifs.if_facility_planning_flag fif_facility_planning_flag,
ifs.if_deletion_mark fif_if_deletion_mark,
ifs.if_allocation_fence_date fif_allocation_fence_date,
ifs.misr_id fif_misr_id,
ifs.misr_me_id fif_me_id,
ifs.item_mat_id fif_item_mat_id,
ifs.item_prit_id fif_item_prit_id,
ifs.item_papl_id fif_item_papl_id,
ifs.item_repi_id fif_item_repi_id,
ifs.item_tnr fif_item_tnr,
ifs.item_id fif_item_id,
ifs.btyp_id fif_btyp_id,
ifs.btyp_basic_type fif_basic_type,
sprd_sales_name fif_sprd_sales_name,
bno_id fif_bno_id,
bno_baunumber fif_bno,
bno_deletion_mark fif_bno_deletion_mark,
bno_demand_level_code fif_bno_demand_level_code,
pg_id fif_pg_id,
pl_process_line fif_pl_process_line,
pl_id fif_pl_id,
pcl_process_class fif_pcl_process_class,
pcl_id fif_pcl_id,
pgp_id fif_pgp_id,
DECODE(bs1.bs_id, NULL,DECODE(bs2.bs_id, NULL, bs3.bs_id, bs2.bs_id), bs1.bs_id) fif_bs_id,
DECODE(bs1.bs_business_segment, NULL,
DECODE(bs2.bs_business_segment, NULL, bs3.bs_business_segment, bs2.bs_business_segment), bs1.bs_business_segment) fif_bs_business_segment,
fac_id fif_fac_id,
fac_facility_name fif_fac_name,
fac_facility_type fif_fac_type,
fac_usable_from fif_fac_usable_from,
fac_usable_to fif_fac_usable_to,
fac_loc_id fif_fac_loc_id,
loc_location fif_fac_loc_location,
si1.site_id fif_site_id,
si1.site_site_name fif_site_name,
si2.site_id fif_site_id_fm,
si2.site_site_name fif_site_name_fm,
sc1.sc_id fif_sc_id,
sc1.sc_supply_chain_name fif_sc_name,
sc1.sc_type fif_sc_type,
sc1.sc_eng_id fif_sc_eng_id,
sc2.sc_id fif_sc_id_fm,
sc2.sc_supply_chain_name fif_sc_name_fm,
sc2.sc_type fif_sc_type_fm,
sc2.sc_eng_id fif_sc_eng_id_fm,
pk_id fif_pk_id,
pk_package_name fif_package_name,
eng_ignore_key_wc fif_eng_ignore_key_wc,
dbi_id fif_dbi_id,
bno_rias_user fif_bno_rias_user,
bno_production_arranger fif_bno_production_arranger
, if_merchandise_flag fif_merchandise_flag
FROM
(SELECT
ifsel.*,
misr_id,
misr_me_id,
item_mat_id,
item_prit_id,
item_papl_id,
item_repi_id,
item_tnr,
item_id,
item_sisc_id,
me_pk_id,
decode (if_misr_id, null, nvl(btyp2.btyp_id,0), btyp1.btyp_id) btyp_id,
decode (if_misr_id, null, nvl(btyp2.btyp_basic_type, 'UNDEF.'), btyp1.btyp_basic_type) btyp_basic_type,
decode (if_misr_id, null, nvl(btyp2.btyp_pl_id, 0), btyp1.btyp_pl_id) btyp_pl_id
FROM
basic_types btyp1,
basic_types btyp2,
processed_items,
items,
mi_subroutes,
mi_elements,
item_facilities ifsel
WHERE
ifsel.if_item_id = item_id
AND ifsel.if_misr_id = misr_id(+)
AND item_prit_id = prit_id (+)
AND prit_btyp_id = btyp2.btyp_id (+)
AND misr_me_id = me_id(+)
AND me_btyp_id = btyp1.btyp_id(+)
AND ifsel.if_type <> 'K'
AND
(item_prit_id is not null
OR item_repi_id is not null
OR item_sisc_id is not null)) ifs,
manufacturing_levels,
start_item_scs,
business_segments bs3,
sites si1,
supply_chains sc1,
sites si2,
supply_chains sc2,
engines,
database_instances,
facilities,
locations,
packages,
representative_items,
business_segments bs2,
process_lines,
process_groups,
process_classes,
baunumbers,
product_groups,
business_segments bs1,
sales_products
WHERE
ifs.if_ml_id = ml_id
AND ml_level_type <> 'UNDEF'
AND ifs.item_sisc_id = sisc_id(+)
AND sisc_bs_id = bs3.bs_id(+)
AND ifs.if_site_id = si1.site_id(+)
AND si1.site_sc_id = sc1.sc_id(+)
AND si1.site_site_id = si2.site_id(+)
AND si2.site_sc_id = sc2.sc_id(+)
AND sc2.sc_eng_id = eng_id(+)
AND eng_dbi_id = dbi_id(+)
AND ifs.if_fac_id = fac_id
AND fac_loc_id = loc_id
AND ifs.me_pk_id = pk_id(+)
AND ifs.item_repi_id = repi_id(+)
AND repi_bs_id = bs2.bs_id(+)
AND ifs.btyp_pl_id = pl_id(+)
AND pl_pgp_id = pgp_id (+)
AND pgp_pcl_id = pcl_id (+)
AND ifs.if_bno_id = bno_id(+)
AND bno_pg_id = pg_id(+)
AND pg_bs_id = bs1.bs_id(+)
AND ifs.if_bno_id = sprd_bno_id(+)
AND (bs1.bs_id is not null OR bs2.bs_id is not null OR bs3.bs_id is not null)
AND (bno_baunumber is not null OR ifs.item_tnr is not null)
AND (bno_deletion_mark is null OR ml_level_type = 'VKL')
Explain plan for select * from v_fif order by fif_if_id;
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
Plan hash value: 62762906
| Id | Operation | Name
| 0 | SELECT STATEMENT |
| 1 | SORT ORDER BY |
| 2 | NESTED LOOPS |
|* 3 | FILTER |
| 4 | NESTED LOOPS OUTER |
| 5 | NESTED LOOPS OUTER |
| 6 | NESTED LOOPS OUTER |
| 7 | NESTED LOOPS OUTER |
| 8 | NESTED LOOPS OUTER |
| 9 | NESTED LOOPS OUTER |
| 10 | NESTED LOOPS OUTER |
| 11 | NESTED LOOPS OUTER |
| 12 | NESTED LOOPS |
| 13 | NESTED LOOPS |
| 14 | NESTED LOOPS OUTER |
PLAN_TABLE_OUTPUT
| 15 | NESTED LOOPS OUTER |
| 16 | NESTED LOOPS OUTER |
| 17 | NESTED LOOPS OUTER |
| 18 | NESTED LOOPS OUTER |
| 19 | NESTED LOOPS OUTER |
| 20 | NESTED LOOPS OUTER |
| 21 | NESTED LOOPS OUTER |
| 22 | NESTED LOOPS OUTER |
| 23 | NESTED LOOPS OUTER |
| 24 | VIEW |
| 25 | NESTED LOOPS OUTER |
| 26 | NESTED LOOPS OUTER |
| 27 | NESTED LOOPS OUTER |
| 28 | NESTED LOOPS |
| 29 | NESTED LOOPS OUTER |
| 30 | NESTED LOOPS OUTER |
|* 31 | TABLE ACCESS FULL | ITEM_FACILIT
| 32 | TABLE ACCESS BY INDEX ROWID| MI_SUBROUTES
|* 33 | INDEX UNIQUE SCAN | MISR_PK
| 34 | TABLE ACCESS BY INDEX ROWID | MI_ELEMENTS
|* 35 | INDEX UNIQUE SCAN | ME_PK
PLAN_TABLE_OUTPUT
|* 36 | TABLE ACCESS BY INDEX ROWID | ITEMS
|* 37 | INDEX UNIQUE SCAN | ITEM_PK
| 38 | TABLE ACCESS BY INDEX ROWID | PROCESSED_IT
|* 39 | INDEX UNIQUE SCAN | PRIT_PK
| 40 | TABLE ACCESS BY INDEX ROWID | BASIC_TYPES
|* 41 | INDEX UNIQUE SCAN | BTYP_PK
| 42 | TABLE ACCESS BY INDEX ROWID | BASIC_TYPES
|* 43 | INDEX UNIQUE SCAN | BTYP_PK
| 44 | TABLE ACCESS BY INDEX ROWID | SALES_PRODUC
|* 45 | INDEX UNIQUE SCAN | SPRD_SPRD1_U
| 46 | TABLE ACCESS BY INDEX ROWID | BAUNUMBERS
|* 47 | INDEX UNIQUE SCAN | BNO_PK
| 48 | TABLE ACCESS BY INDEX ROWID | PRODUCT_GROU
|* 49 | INDEX UNIQUE SCAN | PG_PK
| 50 | TABLE ACCESS BY INDEX ROWID | BUSINESS_SEG
|* 51 | INDEX UNIQUE SCAN | BS_PK
| 52 | TABLE ACCESS BY INDEX ROWID | PROCESS_LINE
|* 53 | INDEX UNIQUE SCAN | PL_PK
| 54 | TABLE ACCESS BY INDEX ROWID | PROCESS_GROU
|* 55 | INDEX UNIQUE SCAN | PGP_PK
| 56 | TABLE ACCESS BY INDEX ROWID | PROCESS_CLAS
PLAN_TABLE_OUTPUT
|* 57 | INDEX UNIQUE SCAN | PCL_PK
| 58 | TABLE ACCESS BY INDEX ROWID | REPRESENTATI
|* 59 | INDEX UNIQUE SCAN | REPI_PK
| 60 | TABLE ACCESS BY INDEX ROWID | BUSINESS_SEG
|* 61 | INDEX UNIQUE SCAN | BS_PK
| 62 | TABLE ACCESS BY INDEX ROWID | PACKAGES
|* 63 | INDEX UNIQUE SCAN | PK_PK
| 64 | TABLE ACCESS BY INDEX ROWID | FACILITIES
|* 65 | INDEX UNIQUE SCAN | FAC_PK
| 66 | TABLE ACCESS BY INDEX ROWID | LOCATIONS
|* 67 | INDEX UNIQUE SCAN | LOC_PK
| 68 | TABLE ACCESS BY INDEX ROWID | SITES
|* 69 | INDEX UNIQUE SCAN | SITE_PK
| 70 | TABLE ACCESS BY INDEX ROWID | SITES
|* 71 | INDEX UNIQUE SCAN | SITE_PK
| 72 | TABLE ACCESS BY INDEX ROWID | SUPPLY_CHAIN
|* 73 | INDEX UNIQUE SCAN | SC_PK
| 74 | TABLE ACCESS BY INDEX ROWID | ENGINES
|* 75 | INDEX UNIQUE SCAN | ENG_PK
|* 76 | INDEX UNIQUE SCAN | DBI_PK
| 77 | TABLE ACCESS BY INDEX ROWID | SUPPLY_CHAIN
PLAN_TABLE_OUTPUT
|* 78 | INDEX UNIQUE SCAN | SC_PK
| 79 | TABLE ACCESS BY INDEX ROWID | START_ITEM_S
|* 80 | INDEX UNIQUE SCAN | SISC_PK
| 81 | TABLE ACCESS BY INDEX ROWID | BUSINESS_SEG
|* 82 | INDEX UNIQUE SCAN | BS_PK
|* 83 | TABLE ACCESS BY INDEX ROWID | MANUFACTURIN
|* 84 | INDEX UNIQUE SCAN | ML_PK
Predicate Information (identified by operation id):
3 - filter("BS1"."BS_ID" IS NOT NULL OR "BS2"."BS_ID" IS NOT NULL OR
"BS3"."BS_ID" IS NOT NULL)
31 - filter("IFSEL"."IF_TYPE"<>'K')
33 - access("IFSEL"."IF_MISR_ID"="MISR_ID"(+))
35 - access("MISR_ME_ID"="ME_ID"(+))
36 - filter("ITEM_PRIT_ID" IS NOT NULL OR "ITEM_REPI_ID" IS NOT NULL OR
"ITEM_SISC_ID" IS NOT NULL)
37 - access("IFSEL"."IF_ITEM_ID"="ITEM_ID")
39 - access("ITEM_PRIT_ID"="PRIT_ID"(+))
PLAN_TABLE_OUTPUT
41 - access("PRIT_BTYP_ID"="BTYP2"."BTYP_ID"(+))
43 - access("ME_BTYP_ID"="BTYP1"."BTYP_ID"(+))
45 - access("IFS"."IF_BNO_ID"="SPRD_BNO_ID"(+))
47 - access("IFS"."IF_BNO_ID"="BNO_ID"(+))
49 - access("BNO_PG_ID"="PG_ID"(+))
51 - access("PG_BS_ID"="BS1"."BS_ID"(+))
53 - access("IFS"."BTYP_PL_ID"="PL_ID"(+))
55 - access("PL_PGP_ID"="PGP_ID"(+))
57 - access("PGP_PCL_ID"="PCL_ID"(+))
59 - access("IFS"."ITEM_REPI_ID"="REPI_ID"(+))
61 - access("REPI_BS_ID"="BS2"."BS_ID"(+))
63 - access("IFS"."ME_PK_ID"="PK_ID"(+))
65 - access("IFS"."IF_FAC_ID"="FAC_ID")
67 - access("FAC_LOC_ID"="LOC_ID")
69 - access("IFS"."IF_SITE_ID"="SI1"."SITE_ID"(+))
71 - access("SI1"."SITE_SITE_ID"="SI2"."SITE_ID"(+))
73 - access("SI2"."SITE_SC_ID"="SC2"."SC_ID"(+))
75 - access("SC2"."SC_ENG_ID"="ENG_ID"(+))
76 - access("ENG_DBI_ID"="DBI_ID"(+))
78 - access("SI1"."SITE_SC_ID"="SC1"."SC_ID"(+))
80 - access("IFS"."ITEM_SISC_ID"="SISC_ID"(+))
PLAN_TABLE_OUTPUT
82 - access("SISC_BS_ID"="BS3"."BS_ID"(+))
83 - filter(("BNO_DELETION_MARK" IS NULL OR "ML_LEVEL_TYPE"='VKL') AND
"ML_LEVEL_TYPE"<>'UNDEF')
84 - access("IFS"."IF_ML_ID"="ML_ID")
Note
- rule based optimizer used (consider using cbo)
133 rows selectedAny help really appreciated
Thanks in advanceI will suggest two things for your problem.
1. Try to remove all the decode operation with case .
2. If possible use CBO instead of RBO.
As you said that CBO is taking more time .. You must gather statistics about the objects.
and then use the CBO.
And a full table scan not always stands for the performance problems.It depends on the cardinality of
your SQL Statement.
Your explain plan output also shows a view operation is taking place, so try to rewrite the view in some other
possible way so that the view can become mergable with the main query.
It will defenitely help you.
Bi tc -
Query can't be rewritten by a Materialized View
Hi All,
The structure of Materialized view looks like:
select
T1483342.MEASR_AMT as c4,
T1482315.MTH_NAME as c8
from
MMM T1483380,
AN_VSBL_IND_LKP T1483226,
AMM T1484452 ,
ND_ASDN_DIM T1483850,
_FDIM T1482018,
R_DIM T1482315,
AN_FCT T1483342
where (JOINS)
And it has 'ENABLE QUERY REWRITE' clause.
If I run the query like this, the query rewritten is used by CBO and seems fine to me.
select
T1483342.MEASR_AMT as c4,
T1482315.MTH_NAME as c8
from
MMM T1483380,
AN_VSBL_IND_LKP T1483226,
AMM T1484452 ,
ND_ASDN_DIM T1483850,
_FDIM T1482018,
R_DIM T1482315,
AN_FCT T1483342
where (JOINS)
But if I run the query like the following one, query rewritten can't happen with the following reason:
QSM-01072: materialized view, LEON_SVP_NEW1, and query have different joins between tables.
select
sum(T1483342.MEASR_AMT) as c4,
T1482315.MTH_NAME as c8
from
MMM T1483380,
AN_VSBL_IND_LKP T1483226,
AMM T1484452 ,
ND_ASDN_DIM T1483850,
_FDIM T1482018,
R_DIM T1482315,
AN_FCT T1483342
where (JOINS)
group by T1482315.MTH_NAME
order by c8
The only difference between the 2 query is one has aggregation on one column but the other does not.
Can someone give me some advice on why the latter query is not rewritten by CBO, please?
Thank you very much,
Leon
Edited by: user12064076 on Feb 15, 2011 7:22 PMThe error message is
QSM-01072: materialized view, string, and query have different joins between tables, string
Cause: Anchors, if any, in the MV and query match. But the joins between these anchors in the MV and query are different.
Action: None
That would mean that the JOINs are different.
Edited by: Hemant K Chitale on Feb 16, 2011 11:34 AM
Edited by: Hemant K Chitale on Feb 16, 2011 11:34 AM -
Materialized View Not Picked Up
Hopefully I'm doing something wrong, because so far
Materialized Views are useless. What's happening
is that the MV is only picked up by a select
statement when the select is identical to the MV
query - this means that we'd have to create a
separate MV for each possible query.
Here's an example:
create materialized view
FACT_DIM04_LVL02
enable query rewrite
as
select
d04.DKEY
, d04.LVL02_DESCR
, f.KEY01
, f.KEY03
, f.YEAR_MONTH
, f.SCENARIO
, sum(f.AMOUNT) "AMOUNT"
from FACT1 f
, DIM04 d04
where (f.KEY04 = d04.KEY04)
and (f.ATTR01 = 'O')
and (d04.LVL01_DESCR = '9999')
and (f.SCENARIO IN ('ACT', 'PLAN'))
group by
d04.DKEY
, d04.LVL02_DESCR
, f.KEY01
, f.KEY03
, f.YEAR_MONTH
, f.SCENARIO
analyze table FACT_DIM04_LVL02 compute statistics ;
So far so good. Now let's do an EXPLAIN using the exact
same DDL used to create the MV:
explain plan
set STATEMENT_ID = 'FACT04'
for
select
d04.DKEY
, d04.LVL02_DESCR
, f.KEY01
, f.KEY03
, f.YEAR_MONTH
, f.SCENARIO
, sum(f.AMOUNT) "AMOUNT"
from FACT1 f
, DIM04 d04
where (f.KEY04 = d04.KEY04)
and (f.ATTR01 = 'O')
and (d04.LVL01_DESCR = '9999')
and (f.SCENARIO IN ('ACT', 'PLAN'))
group by
d04.DKEY
, d04.LVL02_DESCR
, f.KEY01
, f.KEY03
, f.YEAR_MONTH
, f.SCENARIO
This gives:
Query Plan
SELECT STATEMENT Cost = 602
TABLE ACCESS FULL FACT_DIM04_LVL02
Great. However, now let's add one tiny little additional
where clause to the query:
explain plan
set STATEMENT_ID = 'FACT04'
for
select /*+ REWRITE */
d04.DKEY
, d04.LVL02_DESCR
, f.KEY01
, f.KEY03
, f.YEAR_MONTH
, f.SCENARIO
, sum(f.AMOUNT) "AMOUNT"
from FACT1 f
, DIM04 d04
where (f.KEY04 = d04.KEY04)
and (f.ATTR01 = 'O')
and (d04.LVL01_DESCR = '9999')
and (f.SCENARIO IN ('ACT', 'PLAN'))
and (1 = 1)
group by
d04.DKEY
, d04.LVL02_DESCR
, f.KEY01
, f.KEY03
, f.YEAR_MONTH
, f.SCENARIO
Notice that I added the simplest predicate possible
(1 = 1), AND I've added a hint telling the optimizer
to use the new MV. However, Oracle does not recognize
the MV; instead it goes back to the base tables:
Query Plan
SELECT STATEMENT Cost = 4130
SORT GROUP BY
HASH JOIN
TABLE ACCESS BY INDEX ROWID DIM04
INDEX RANGE SCAN DIM04_LVL02
TABLE ACCESS FULL FACT_DIM04_LVL02
In other words, this MV only seems to work if you're using
the EXACT query that was used to create the MV, which
makes it almost useless.
I notice that in DBA_MVIEWS, there's a field called
REWRITE_CAPABILITY, and this has a value of TEXTMATCH:
SQLlist
1 select mview_name, rewrite_enabled, rewrite_capability
2* from dba_mviews
SQL/
MVIEW_NAME R REWRITE_C
FACT_DIM04_LVL02 Y TEXTMATCH
TEST01 Y GENERAL
Here's what the manual says about this:
TEXTMATCH: The defining query of the materialized view
contained restrictions on the use of query rewrite.
Yes, I'm using CBO and have set QUERY REWRITE to true.
Also, should it matter, we're on 8.17, Sun Solaris 2.7
Any ideas out there? TIA.What is the value of the job_queue_processes initialization parameter?
Check dba|all|user_jobs to see if a refresh is actually scheduled and not marked broken.
If a job is present, what is the value of the next_date column? -
Should I use materialised view?
I am using the following sql in my code. This takes a long time to execute and I need to tune this. Please review and suggest if I should be using a materialized view instead.
Main Select statement for interest calculation
SELECT intratechgcur.SECURITY, intratechgcur.srl_no, intratechgcur.schg_type,
CASE WHEN intratechgcur.effective_date < ADt_Start_Date THEN ADt_Start_Date
ELSE intratechgcur.effective_date END AS start_date,
CASE WHEN intratechgcur.effective_date < ADt_End_Date
AND NVL(intratechgnext.effective_date, ADt_End_Date) > ADt_End_Date THEN ADt_End_Date
ELSE NVL(intratechgnext.effective_date, ADt_End_Date) END AS end_date,
intratechgcur.rate, intratechgcur.face_value, intratechgcur.listing_int, intratechgcur.comm_prod_int,
intratechgcur.sec_create_int, intratechgcur.int_type, intratechgcur.interest_key, intratechgcur.margin,
intratechgcur.FLOOR, intratechgcur.cap, intratechgcur.reset_freq, intratechgcur.cmpd_y_n, intratechgcur.cmpd_freq,
intratechgcur.comp_type, intratechgcur.int_day, intratechgcur.int_day_1, intratechgcur.int_day_2, intratechgcur.int_dtls_yn
FROM v_intratechg intratechgcur, v_intratechg intratechgnext
WHERE intratechgcur.SECURITY = AS_Security
AND intratechgcur.effective_date < ADt_End_Date
AND intratechgnext.SECURITY (+)= intratechgcur.SECURITY
AND intratechgnext.srl_no (+)= intratechgcur.srl_no + 1
ORDER BY intratechgcur.SECURITY, intratechgcur.effective_date, intratechgcur.srl_no ;
The code for the view V_intratechg is;
CREATE OR REPLACE VIEW V_INTRATECHG AS
SELECT security,
schg_type,
effective_date,
SUM(1) over (PARTITION BY security ORDER BY security, effective_date ASC, schg_type ASC) AS srl_no,
face_value,
rate,
listing_int,
comm_prod_int,
sec_create_int,
int_type,
interest_key,
margin,
FLOOR,
cap,
NVL(reset_freq, 'DAILY') AS reset_freq,
NVL(cmpd_y_n, 'N') AS cmpd_y_n,
NVL(cmpd_freq, 'DAILY') AS cmpd_freq,
NVL(comp_type, 'N') AS comp_type,
int_day, int_day_1, int_day_2, int_dtls_yn
FROM
(SELECT security.security, 'IM' AS schg_type,
GREATEST(security.prv_int_dt, NVL(security.allot_date, security.prv_int_dt),
NVL(security.first_int_date,security.prv_int_dt)) AS effective_date,
DECODE(intday.int_day_1, 'ACD', NVL((SELECT interest_amt FROM securityschddtls A WHERE security.security = A.security
AND A.adhoc_schd_date > GREATEST(security.prv_int_dt, NVL(security.allot_date, security.prv_int_dt),
NVL(security.first_int_date,security.prv_int_dt))
AND a.rectype ='L' AND A.ADHOC_SCHD_DATE = (SELECT MIN(ADHOC_SCHD_DATE) FROM securityschddtls
WHERE securityschddtls.adhoc_schd_date > GREATEST(security.prv_int_dt, NVL(security.allot_date, security.prv_int_dt), NVL(security.first_int_date,security.prv_int_dt))
AND securityschddtls.security = A.security AND securityschddtls.rectype='L')),
NVL(secchg.rate, security.interest)), NVL(secchg.rate, security.interest)) AS rate,
NVL(secchg.face_value, security.face_value) AS face_value,
NVL(secchg.listing_int, security.listing_int) AS listing_int,
NVL(secchg.comm_prod_int, security.comm_prod_int) AS comm_prod_int,
NVL(secchg.sec_create_int,security.sec_create_int) AS sec_create_int,
NVL(secchg.int_type, security.int_type) AS int_type,
NVL(secchg.interest_key, security.interest_key) AS interest_key,
NVL(secchg.margin, security.margin) AS margin,
NVL(secchg.FLOOR, security.FLOOR) AS FLOOR,
NVL(secchg.cap, security.cap) AS cap,
NVL(secchg.reset_freq, security.reset_freq) AS reset_freq,
NVL(secchg.cmpd_y_n, security.cmpd_y_n) AS cmpd_y_n,
NVL(secchg.cmpd_freq, security.cmpd_freq) AS cmpd_freq,
NVL(secchg.comp_type, security.comp_type) AS comp_type,
NVL(secchg.int_day, security.int_day) AS int_day, intday.int_day_1,
intday.int_day_2, 'Y' AS int_dtls_yn
FROM security, assetype, intday, securityschddtls secdtls,
(SELECT secchg.security AS security, secchg.call_date AS effective_date,
NVL(secchg.rate,0) AS rate, secchg.face_value,
SUM(1) over (PARTITION BY secchg.security ORDER BY secchg.security,
secchg.call_date ASC) AS srl_no,
NVL(secchg.listing_int,0) AS listing_int, NVL(secchg.comm_prod_int,0) AS comm_prod_int,
NVL(secchg.sec_create_int,0) AS sec_create_int,
secchg.int_type, secchg.interest_key,
nvl(secchg.margin,0) as margin, nvl(secchg.FLOOR,0) as floor,
nvl(secchg.cap,0) as cap, secchg.reset_freq,
secchg.cmpd_y_n, secchg.cmpd_freq, secchg.comp_type, secchg.int_day FROM secchg) secchg
WHERE security.asset_type = assetype.asset_type
AND security.int_day = intday.int_day
AND assetype.int_y_n = 'Y'
AND security.rectype = 'L'
AND assetype.rectype = 'L'
AND intday.rectype = 'L'
AND secchg.security (+)= security.security
AND secchg.srl_no (+)= 1
AND secdtls.security (+)= security.security
AND secdtls.srl_no (+)= 1
AND secdtls.rectype (+)= 'L'
UNION ALL
SELECT schedules.security,
DECODE(schedules.schd_past_yn, 'Y', 'RP', 'RS') AS schg_type,
DECODE(intday.int_day_1, 'ACD',security_cashflow.start_date,security_cashflow.inflow_date) AS effective_date,
--commented by vijai
-- DECODE(intday.int_day_1, 'ACD', intschdamt.amount, NVL(intratechg.rate,security.interest)) AS rate,
DECODE(intday.int_day_1, 'ACD', intschdamt.amount,decode(security_cashflow.start_Date,intratechg.value_Date, intratechg.rate, security.interest)) as rate,
decode(nvl(schedules.tot_face_value - schedules.cum_face_value,security.face_value),0,security.face_value,schedules.tot_face_value - schedules.cum_face_value,security.face_value) AS face_value,
NVL(intratechg.listing_int,security.listing_int) as listing_int,
NVL(intratechg.comm_prod_int,security.comm_prod_int) as comm_prod_int,
NVL(intratechg.sec_create_int,security.sec_create_int),
NVL(intratechg.int_type,security.int_type) as int_type,
nvl(intratechg.interest_key,security.interest_key) as interest_key,
nvl(intratechg.margin,security.margin) as margin,
nvl(intratechg.FLOOR,security.floor) as floor,
nvl(intratechg.cap,security.cap) as cap,
nvl(intratechg.reset_freq,security.reset_freq) as reset_freq,
nvl(intratechg.cmpd_y_n,security.cmpd_y_n) as cmpd_y_n,
nvl(intratechg.cmpd_freq,security.cmpd_freq) as cmpd_freq,
nvl(intratechg.comp_type,security.comp_type),
nvl(intratechg.int_day,security.int_day),
intday.int_day_1, intday.int_day_2,
DECODE(intratechg.security, NULL, 'N', 'Y') AS int_dtls_yn
FROM v_schedules schedules, security, intday, intratechg, v_schedules intschdamt, security_cashflow
WHERE schedules.security = security.security
AND schedules.red_yn = 'Y'
AND security.int_day = intday.int_day
AND security.rectype = 'L'
AND intday.rectype = 'L'
AND intratechg.security (+)= schedules.security
AND intratechg.value_date(+)= schedules.schd_date
AND intratechg.rectype (+)= 'L'
AND intschdamt.security (+)= schedules.security
AND intschdamt.schd_date (+)= schedules.schd_date
AND intschdamt.red_yn (+)= 'N'
AND security_cashflow.inflow_type = 'INT'
AND security_cashflow.inflow_date = schedules.schd_date
AND security.security = security_cashflow.security
AND schedules.security = security_cashflow.security
UNION ALL
SELECT intratechg.security, 'IR' AS schg_type,
intratechg.value_date AS effective_date,
NVL(intratechg.rate,security.interest),
security.face_value,
NVL(intratechg.listing_int,security.listing_int),
NVL(intratechg.comm_prod_int,security.comm_prod_int),
NVL(intratechg.sec_create_int,security.sec_create_int),
nvl(intratechg.int_type,security.int_type),
nvl(intratechg.interest_key,security.interest_key),
nvl(intratechg.margin,security.margin),
nvl(intratechg.FLOOR,security.floor),
nvl(intratechg.cap,security.cap),
nvl(intratechg.reset_freq,security.reset_freq),
nvl(intratechg.cmpd_y_n,security.cmpd_y_n),
nvl(intratechg.cmpd_freq,security.cmpd_freq),
nvl(intratechg.comp_type,security.comp_type),
nvl(intratechg.int_day,security.int_day),
intday.int_day_1, intday.int_day_2, 'Y' AS int_dtls_yn
FROM intratechg, security, intday
WHERE intratechg.security = security.security
AND security.int_day = intday.int_day
AND intratechg.rectype = 'L'
AND security.rectype = 'L'
AND intday.rectype = 'L'
AND NOT EXISTS (SELECT 1 FROM v_schedules schedules
WHERE schedules.security = intratechg.security
AND schedules.schd_date = intratechg.value_date
AND schedules.red_yn = 'Y'))
ORDER BY security, srl_no
The code for the view V_schedules is;
CREATE OR REPLACE VIEW V_SCHEDULES AS
SELECT schdall.security,
schdall.schd_date,
schdall.schd_type,
schdall.percent,
schdall.units_o,
schdall.units_n,
schdall.amount,
schdall.sequences,
schdall.act_sch_dt,
schdall.security_n,
schdall.prior_act,
schdall.red_amount,
schdall.ben_refer,
schdall.round_method,
schdall.round_dec,
schdall.average_y_n,
schdall.schd_past_yn,
CASE WHEN schd_type IN(sysschd.red, sysschd.disred) THEN 'Y' ELSE 'N' END AS red_yn,
SUM( CASE WHEN schd_type IN(sysschd.red, sysschd.disred) THEN schdall.red_amount ELSE 0 END)
over(PARTITION BY schdall.security) AS tot_face_value,
SUM( CASE WHEN schd_type IN(sysschd.red, sysschd.disred) THEN schdall.red_amount ELSE 0 END)
over(PARTITION BY schdall.security
ORDER BY schdall.security, schdall.schd_date ASC) AS cum_face_value,
SUM( CASE WHEN schd_type IN(sysschd.red, sysschd.disred) THEN schdall.red_amount ELSE 0 END)
over(PARTITION BY schdall.security
ORDER BY schdall.security, schdall.schd_date DESC) AS to_be_redeemed ,
SUM(CASE WHEN schd_type =sysschd.INT THEN 0 ELSE 1 END)
over(PARTITION BY schdall.security,schdall.schd_date,schd_type)
AS no_of_schd
FROM
(SELECT schedules.security_o AS security,
schedules.schd_date,
schedules.schd_type,
schedules.percent,
schedules.units_o,
schedules.units_n,
schedules.amount,
schedules.sequences,
schedules.act_sch_dt,
schedules.security_n,
schedules.prior_act,
schedules.red_amount,
schedules.ben_refer,
schedules.round_method,
schedules.round_dec,
schedules.average_y_n,
DECODE(schedules.schd_type,'RED','Y','Y') AS schd_past_yn
FROM schdpast schedules
WHERE prior_act = 'A'
AND rectype = 'L'
UNION ALL
SELECT schedules.security_o AS security,
schedules.schd_date,
schedules.schd_type,
schedules.percent,
schedules.units_o,
schedules.units_n,
schedules.amount,
schedules.sequences,
schedules.act_sch_dt,
schedules.security_n,
schedules.prior_act,
schedules.red_amount,
schedules.ben_refer,
schedules.round_method,
schedules.round_dec,
schedules.average_y_n,
'N' AS schd_past_yn
FROM schedules
WHERE prior_act = 'A'
AND rectype = 'L'
AND Process_date IS NULL ) schdall,
(SELECT MAX(redschdtype) AS red,
MAX(disredtype) AS disred,
MAX(intschdtype) AS INT
FROM sysparamschd
WHERE rectype = 'L') sysschd
ORDER BY security, schd_date, schd_typeToo much SQL... makes me eyes hurt.
I think you're running down the wrong alley here. The very first and fundamental principle of performance tuning is identifying the performance problem. Saying that there is a problem is not identifying the actual problem.
You cannot run down the alley with a knife looking for a performance problem to kill if you do not know how it looks like. Good that you are running though - the old Klingon saying of "a running warrior can slit more throats" hold very true. :-)
Why is the existing SQL slow? You first need to identify that. Sure, a materialised view can make the end-query much faster as it has no longer to do all the work - that has now been done in batch by a DBMS_REFRESH job updating and maintaining that materialised view. But that work is still done... so have you actually fixed the cause of the performance problem, or merely hid it by addressing the symptoms?
How does one find and identify the underlaying performance problem with too-much-SQL-that-makes-Billy's-eyes-hurt? Software Engineering 101. Take any complex problem. Break it down into lots of smaller little problems. Solve each on in turn.
Take the SQL, break it down into simpler pieces and check each for performance issues. Look at the execution plan and cost. Determime if you (via the physical db design) are providing optimal I/O paths to the CBO in order for it to get to the required data with as little I/O as possible.
Once you deal with the facts, you can make an informed decision or whether or not a materialised view will actually fix the cause of the performance problem. -
10g query running faster with RBO than CBO
I am running a query in Oracle 10g that is taking 1minute 15 seconds to run using the CBO. All the tables and indexes in the query are fully analyzed. However if i add a /*+ Rule */ hint to the query and force the optimizer to RBO it runs in 5 seconds.
Anyone any ideas why this would occur? it's contrary to everything Oracle says about CBO and problematic as RBO is no longer supported in 10g
Any help / advice greatfully appreciated
Thanks
DeclanMy "best" CBO explain plan is......
Explain complete.
Elapsed: 00:00:01:90
PLAN_TABLE_OUTPUT
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost |
| 0 | SELECT STATEMENT | | 3364K| 2553M| | 666K|
| 1 | SORT ORDER BY | | 3364K| 2553M| 5840M| 666K|
| 2 | VIEW | | 3364K| 2553M| | 273K|
| 3 | UNION-ALL | | | | | |
|* 4 | HASH JOIN | | 2269K| 1415M| | 255K|
|* 5 | TABLE ACCESS FULL | NODE | 6 | 198 | | 183 |
|* 6 | HASH JOIN OUTER | | 2269K| 1344M| | 255K|
|* 7 | HASH JOIN | | 710 | 266K| | 2179 |
|* 8 | HASH JOIN OUTER | | 1219 | 165K| | 355 |
|* 9 | HASH JOIN | | 1219 | 154K| | 318 |
|* 10 | HASH JOIN | | 1219 | 138K| | 260 |
|* 11 | HASH JOIN | | 1219 | 127K| | 224 |
| 12 | TABLE ACCESS FULL | TMP_NODE_WALK_ALL_NODES | 8168 | 311K| | 17 |
|* 13 | HASH JOIN | | 10896 | 723K| | 201 |
| 14 | INDEX FAST FULL SCAN | PK_NODE_RULES_NODE_ID_RULE_ID | 10896 | 106K| | 6 |
| 15 | TABLE ACCESS FULL | NODE | 73004 | 4134K| | 183 |
| 16 | INDEX FAST FULL SCAN | IDX_NODE_CIX2 | 73004 | 641K| | 33 |
PLAN_TABLE_OUTPUT
| 17 | INDEX FAST FULL SCAN | IDX_NODE_CIX1 | 73004 | 998K| | 54 |
| 18 | INDEX FAST FULL SCAN | IDX_NODE_CIX2 | 73004 | 641K| | 33 |
|* 19 | TABLE ACCESS FULL | RULES | 6344 | 1517K| | 1820 |
| 20 | VIEW | | 405M| 89G| | 43581 |
|* 21 | HASH JOIN OUTER | | 405M| 23G| | 43581 |
| 22 | TABLE ACCESS FULL | TMP_NODE_WALK_ALL_NODES | 8168 | 103K| | 17 |
| 23 | TABLE ACCESS FULL | UNIVERSAL_RULES | 3377K| 157M| | 43256 |
|* 24 | HASH JOIN OUTER | | 1094K| 410M| 148M| 17453 |
| 25 | MERGE JOIN CARTESIAN | | 390K| 143M| | 15029 |
| 26 | NESTED LOOPS | | 70 | 25060 | | 2849 |
| 27 | NESTED LOOPS | | 70 | 21000 | | 2779 |
| 28 | TABLE ACCESS BY INDEX ROWID| UNIVERSAL_RULES | 1392 | 76560 | | 1387 |
|* 29 | INDEX RANGE SCAN | IDX_UNIVERSAL_RULES_ACCOUNT | 1392 | | | 6 |
|* 30 | TABLE ACCESS BY INDEX ROWID| RULES | 1 | 245 | | 1 |
|* 31 | INDEX UNIQUE SCAN | PK_RULES_RULE_ID_VERSION_ID | 20 | | | |
|* 32 | TABLE ACCESS BY INDEX ROWID | NODE | 1 | 58 | | 1 |
|* 33 | INDEX UNIQUE SCAN | PK_NODE_NODE_ID | 6 | | | |
| 34 | BUFFER SORT | | 5616 | 153K| | 15028 |
| 35 | TABLE ACCESS BY INDEX ROWID | NODE | 5616 | 153K| | 174 |
|* 36 | INDEX RANGE SCAN | IDX_NODE_NODE_TYPE_ID | 5616 | | | 11 |
|* 37 | INDEX FAST FULL SCAN | IDX_RULES_RULE_ID_STATUS | 42293 | 289K| | 48 |
PLAN_TABLE_OUTPUT
Predicate Information (identified by operation id):
4 - access("NODE"."NODE_TYPE_ID"="SN"."HIERARCHY_TYPE_ID")
5 - filter("NODE"."PARENT_NODE_ID" IS NULL)
6 - access("SYS_ALIAS_1"."RULE_ID"="UR"."RULE_ID"(+) AND "SYS_ALIAS_1"."VERSION_ID"="UR"."VERSION_ID"(+))
7 - access("NR"."RULE_ID"="SYS_ALIAS_1"."COMBINED_RULE_ID")
8 - access("SN"."PARENT_NODE_ID"="SP"."NODE_ID"(+))
9 - access("AN"."START_NODE_ID"="SN"."NODE_ID")
10 - access("AN"."EFFECTIVE_NODE_ID"="EN"."NODE_ID")
11 - access("AN"."SHORTCUT_NODE_ID"="N"."NODE_ID")
13 - access("N"."NODE_ID"="NR"."NODE_ID")
19 - filter(',A,P,' LIKE '%,'||"SYS_ALIAS_1"."STATUS"||',%')
21 - access("UR"."NODE_ID"(+)="AN"."START_NODE_ID")
24 - access("R"."RULE_ID"="RP"."RULE_ID"(+))
29 - access("UR"."ACCOUNT_ID"='0069')
30 - filter(',A,P,' LIKE '%,'||"R"."STATUS"||',%')
31 - access("UR"."RULE_ID"="R"."RULE_ID" AND "UR"."VERSION_ID"="R"."VERSION_ID")
32 - filter("N"."HIERARCHY_TYPE_ID"=9)
PLAN_TABLE_OUTPUT
33 - access("UR"."NODE_ID"="N"."NODE_ID")
36 - access("NODE"."NODE_TYPE_ID"=9)
37 - filter("RP"."STATUS"(+)='P')
Note: cpu costing is off
28 rows selected.
Elapsed: 00:00:02:45
68 rows selected.
Elapsed: 00:00:05:76While my RBO explain plan is
Explain complete.
Elapsed: 00:00:01:23
PLAN_TABLE_OUTPUT
| Id | Operation | Name | Rows | Bytes | Cost |
| 0 | SELECT STATEMENT | | | | |
| 1 | SORT ORDER BY | | | | |
| 2 | VIEW | | | | |
| 3 | UNION-ALL | | | | |
| 4 | MERGE JOIN OUTER | | | | |
| 5 | SORT JOIN | | | | |
|* 6 | TABLE ACCESS BY INDEX ROWID | NODE | | | |
| 7 | NESTED LOOPS | | | | |
| 8 | NESTED LOOPS | | | | |
| 9 | NESTED LOOPS | | | | |
| 10 | NESTED LOOPS | | | | |
| 11 | NESTED LOOPS | | | | |
| 12 | NESTED LOOPS OUTER | | | | |
| 13 | NESTED LOOPS | | | | |
| 14 | TABLE ACCESS FULL | TMP_NODE_WALK_ALL_NODES | | | |
| 15 | TABLE ACCESS BY INDEX ROWID| NODE | | | |
|* 16 | INDEX UNIQUE SCAN | PK_NODE_NODE_ID | | | |
PLAN_TABLE_OUTPUT
| 17 | TABLE ACCESS BY INDEX ROWID | NODE | | | |
|* 18 | INDEX UNIQUE SCAN | PK_NODE_NODE_ID | | | |
| 19 | TABLE ACCESS BY INDEX ROWID | NODE | | | |
|* 20 | INDEX UNIQUE SCAN | PK_NODE_NODE_ID | | | |
| 21 | TABLE ACCESS BY INDEX ROWID | NODE | | | |
|* 22 | INDEX UNIQUE SCAN | PK_NODE_NODE_ID | | | |
| 23 | TABLE ACCESS BY INDEX ROWID | NODE_RULES | | | |
|* 24 | INDEX RANGE SCAN | IDX_NODE_RULES_NODE_ID | | | |
|* 25 | TABLE ACCESS BY INDEX ROWID | RULES | | | |
|* 26 | INDEX RANGE SCAN | IDX_RULES_COMBINED_RULE_ID | | | |
|* 27 | INDEX RANGE SCAN | IDX_NODE_NODE_TYPE_ID | | | |
|* 28 | SORT JOIN | | | | |
| 29 | VIEW | | | | |
| 30 | NESTED LOOPS OUTER | | | | |
| 31 | TABLE ACCESS FULL | TMP_NODE_WALK_ALL_NODES | | | |
| 32 | TABLE ACCESS BY INDEX ROWID | UNIVERSAL_RULES | | | |
|* 33 | INDEX RANGE SCAN | IDX_UNIVERSAL_RULES_NODE | | | |
| 34 | NESTED LOOPS OUTER | | | | |
| 35 | NESTED LOOPS | | | | |
| 36 | NESTED LOOPS | | | | |
| 37 | NESTED LOOPS | | | | |
PLAN_TABLE_OUTPUT
| 38 | TABLE ACCESS BY INDEX ROWID | NODE | | | |
|* 39 | INDEX RANGE SCAN | IDX_NODE_NODE_TYPE_ID | | | |
| 40 | TABLE ACCESS BY INDEX ROWID | UNIVERSAL_RULES | | | |
|* 41 | INDEX RANGE SCAN | IDX_UNIVERSAL_RULES_ACCOUNT | | | |
|* 42 | TABLE ACCESS BY INDEX ROWID | NODE | | | |
|* 43 | INDEX UNIQUE SCAN | PK_NODE_NODE_ID | | | |
|* 44 | TABLE ACCESS BY INDEX ROWID | RULES | | | |
|* 45 | INDEX UNIQUE SCAN | PK_RULES_RULE_ID_VERSION_ID | | | |
|* 46 | INDEX RANGE SCAN | IDX_RULES_RULE_ID_STATUS | | | |
Predicate Information (identified by operation id):
6 - filter("NODE"."PARENT_NODE_ID" IS NULL)
16 - access("AN"."START_NODE_ID"="SN"."NODE_ID")
18 - access("SN"."PARENT_NODE_ID"="SP"."NODE_ID"(+))
20 - access("AN"."EFFECTIVE_NODE_ID"="EN"."NODE_ID")
22 - access("AN"."SHORTCUT_NODE_ID"="N"."NODE_ID")
24 - access("N"."NODE_ID"="NR"."NODE_ID")
25 - filter(',A,P,' LIKE '%,'||"SYS_ALIAS_1"."STATUS"||',%')
PLAN_TABLE_OUTPUT
26 - access("NR"."RULE_ID"="SYS_ALIAS_1"."COMBINED_RULE_ID")
27 - access("NODE"."NODE_TYPE_ID"="SN"."HIERARCHY_TYPE_ID")
28 - access("SYS_ALIAS_1"."RULE_ID"="UR"."RULE_ID"(+))
filter("SYS_ALIAS_1"."VERSION_ID"="UR"."VERSION_ID"(+) AND
"SYS_ALIAS_1"."RULE_ID"="UR"."RULE_ID"(+))
33 - access("UR"."NODE_ID"(+)="AN"."START_NODE_ID")
39 - access("NODE"."NODE_TYPE_ID"=9)
41 - access("UR"."ACCOUNT_ID"='0069')
42 - filter("N"."HIERARCHY_TYPE_ID"=9)
43 - access("UR"."NODE_ID"="N"."NODE_ID")
44 - filter(',A,P,' LIKE '%,'||"R"."STATUS"||',%')
45 - access("UR"."RULE_ID"="R"."RULE_ID" AND "UR"."VERSION_ID"="R"."VERSION_ID")
46 - access("R"."RULE_ID"="RP"."RULE_ID"(+) AND "RP"."STATUS"(+)='P')
Note: rule based optimization
28 rows selected.
Elapsed: 00:00:04:42
78 rows selected.
Elapsed: 00:00:08:86Any additional help appreciated
I am going to try and run a trace against the sql now and see if i can get any more information
Thanks in advance
Declan
Maybe you are looking for
-
After upgrading ACS 3.3.1 to 4.2 on windows the local database is not working
Hi, I have upgaded the ACS 3.3.1 for windows server to 4.2. Everything went fine but the local database is not working. The CD is an upgrade kit from 3.x to 4.2 on windows. I tried to install directly the 4.2 I was able to install but integration wit
-
Mini bridge is not available in Photoshop cc 2014
Typically, I have a min bridge icon but after upgrading to CC2014 It is no longer available. I looked inside and out and it is not here. a forum explained to go to WINDOWS>EXTENSIONS> but that is grayed out. please help. I depend on bridge to
-
Ichat av 3.1.5 (v436) cant make my video work
Hey! Wow, already plenty of topics on this issue. But I tried some things of them and it still doesnt work. I am one of those new-maccers, and was never to good with pcs - and now not so good with mac. Ok, i have one of the new macbooks with built in
-
Do I have a registry problem? Every time I open a PDF file my local Adobe Acrobat (6.0) installation opens AND the file displays in Firefox (v. 4.0.1). When I close the PDF file it tells me other PDF files are open and asks if I'm sure I want to clos
-
'Page Not Found' wifi login issue after ios6 upgrade on iPad2
After upgrading my iPad2 to ios6 and trying to connect to my wifi, my iPad2 tries to login for some reason to the Apple site but all that comes up is a 'Page Not Found' notification. I can browse the Apple site while in this browser but I can only go