Need to reduce table accesses
oracle 9.2.0.8 (if there's a 10G way that would work)
This is a simplified view of a much biiger table I am having to deal with.
create table stg
(ddate date,
num number);
insert into stg
select sysdate, 26 from dual
union all
select sysdate - 1, 38 from dual
union all
select sysdate - 2, 10 from dual
union all
select sysdate - 3, 40 from dual
union all
select sysdate - 4, 50 from dual
union all
select sysdate - 5, 1 from dual
union all
select sysdate - 6, 11 from dual
union all
select sysdate - 7, 50 from dual
union all
select sysdate - 9, 38 from dual
union all
select sysdate - 10, 20 from dual
union all
select sysdate - 11, 11 from dual
union all
select sysdate - 12, 99 from dual
union all
select sysdate - 13, 18 from dual
union all
select sysdate - 14, 27 from dual
union all
select sysdate - 15, 28 from dual
union all
select sysdate - 16, 2 from dual
union all
select sysdate - 17, 99 from dual
union all
select sysdate - 18, 12 from dual
union all
select sysdate - 19, 27 from dual
union all
select sysdate - 20, 28 from dual
select
sum(case when ddate > d.the_date then 1
else 0
end)
,sum(case when ddate < d.the_date then 1
else 0
end)
,the_date
,max(ddate)
from stg, (select min(ddate) as the_date from stg
where num in (10,11,12,13,14,25))d
group by the_date
the query does give me the result set I'm looking for but the explain plan
shows it takes 2 table accesses. My question is how to re-write this so it
takes one access.
I have tried the analytic functions but there does not seem to be a way to
use the where clause in just the analytic function. Also I have tried:
select min(ddate), max(ddate) from stg
where num in (10,11,12,13,14,25)
but the problem with this is the max is the max where num is (10,11,12,13,14,25)not the max of the whole table.
any ideas to get rid of the nested loop would be helpful
thanks
What do you want is not clear for me, but you can try to replace your query :
SCOTT@demo102> select greater,lesser,min_date,max_date
2 from
3 (SELECT
4 SUM(decode(SIGN(ddate -stg_sub."min_date"), 1, 1, 0)) over() AS greater
5 ,SUM(decode(SIGN(ddate -stg_sub."min_date"), -1, 1, 0)) over() AS lesser
6 ,stg_sub."min_date" AS min_date
7 ,stg_sub."max_date" AS max_date
8 ,rownum AS rnum
9 FROM
10 (SELECT
11 ddate
12 ,(SELECT MIN(ddate) FROM stg WHERE num IN(10,11,12,13,14,25)) AS "min_date"
13 ,max(ddate) over() AS "max_date"
14 FROM stg)stg_sub)
15 where rnum = 1
16 ;
GREATER LESSER MIN_DATE MAX_DATE
17 2 26/09/06 14/10/06by
SCOTT@demo102> select sum(greater) greater, sum(lesser) lesser, max(min_date) min_date, max(max_date) max_date
2 from
3 (SELECT
4 case when ddate - MIN(case when num IN(10,11,12,13,14,25) then ddate end) over () > 0 then 1 end AS greater,
5 case when ddate - MIN(case when num IN(10,11,12,13,14,25) then ddate end) over () < 0 then 1 end AS lesser,
6 MIN(case when num IN(10,11,12,13,14,25) then ddate end) over () as min_date,
7 max(ddate) over() AS max_date
8 FROM stg)
9 ;
GREATER LESSER MIN_DATE MAX_DATE
17 2 26/09/06 14/10/06
SCOTT@demo102>
It is a lower cost What did you mean by cost ? Is it cost from explain plan ? Take care, a low cost here doesn't say that your query will run fatser...
Nicolas.
Similar Messages
-
How to make optimizer fetch and join values from Indexes, no table access.
Hi All,
i am having a query which is just checking the existence of the values according to some of the filter criteria, and involves two tables in join. and i want optimizer to find the existence i.e the reult of the query by only accessing indexes only, not to go through table scan using indexes. Is there any way so that i can modify my query or force the optimizer to do the same? below is the existing plan of the query in which its accessing tables using indexes, which causing bottleneck in my DB as these tables are bulky ones.
Execution Plan
Plan hash value: 1209914516
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 1 | | 6 (17)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | | | | | |
|* 2 | FILTER | | | | | | | |
| 3 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | |
| 4 | NESTED LOOPS | | 1 | 24 | 4 (25)| 00:00:01 | | |
| 5 | SORT UNIQUE | | 1 | 10 | 2 (0)| 00:00:01 | | |
| 6 | TABLE ACCESS BY INDEX ROWID | INVOICELINEDISB | 1 | 10 | 2 (0)| 00:00:01 | | |
|* 7 | INDEX RANGE SCAN | IDX_INVLINEDISB_UOMCD | 1 | | 1 (0)| 00:00:01 | | |
| 8 | PARTITION HASH ITERATOR | | 1 | 14 | 1 (0)| 00:00:01 | KEY | KEY |
|* 9 | TABLE ACCESS BY GLOBAL INDEX ROWID| INVOICEHEADERDISB | 1 | 14 | 1 (0)| 00:00:01 | ROWID | ROWID |
|* 10 | INDEX UNIQUE SCAN | P_INVOICEHEADERDISB_PART | 1 | | 0 (0)| 00:00:01 | KEY | KEY |
Predicate Information (identified by operation id):
2 - filter( EXISTS (SELECT 0 FROM "XIGNCMN"."INVOICEHEADERDISB" "INVOICEHEADERDISB","XIGNCMN"."INVOICELINEDISB"
"INVOICELINEDISB" WHERE "INVOICELINEDISB"."UNITOFMEASURECD"='USD' AND
"INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK" AND "INVOICEHEADERDISB"."PAYPK"=8135488395))
7 - access("INVOICELINEDISB"."UNITOFMEASURECD"='USD')
9 - filter("INVOICEHEADERDISB"."PAYPK"=8135488395)
10 - access("INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK")
Statistics
0 recursive calls
0 db block gets
14 consistent gets
0 physical reads
0 redo size
410 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from clientJonathan Lewis wrote:
930254 wrote:
Hi All,
i am having a query which is just checking the existence of the values according to some of the filter criteria, and involves two tables in join. and i want optimizer to find the existence i.e the reult of the query by only accessing indexes only, not to go through table scan using indexes. Is there any way so that i can modify my query or force the optimizer to do the same? below is the existing plan of the query in which its accessing tables using indexes, which causing bottleneck in my DB as these tables are bulky ones.
Execution Plan
Plan hash value: 1209914516
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
| 0 | SELECT STATEMENT | | 1 | | 6 (17)| 00:00:01 | | |
| 1 | SORT AGGREGATE | | 1 | | | | | |
|* 2 | FILTER | | | | | | | |
| 3 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | |
| 4 | NESTED LOOPS | | 1 | 24 | 4 (25)| 00:00:01 | | |
| 5 | SORT UNIQUE | | 1 | 10 | 2 (0)| 00:00:01 | | |
| 6 | TABLE ACCESS BY INDEX ROWID | INVOICELINEDISB | 1 | 10 | 2 (0)| 00:00:01 | | |
|* 7 | INDEX RANGE SCAN | IDX_INVLINEDISB_UOMCD | 1 | | 1 (0)| 00:00:01 | | |
| 8 | PARTITION HASH ITERATOR | | 1 | 14 | 1 (0)| 00:00:01 | KEY | KEY |
|* 9 | TABLE ACCESS BY GLOBAL INDEX ROWID| INVOICEHEADERDISB | 1 | 14 | 1 (0)| 00:00:01 | ROWID | ROWID |
|* 10 | INDEX UNIQUE SCAN | P_INVOICEHEADERDISB_PART | 1 | | 0 (0)| 00:00:01 | KEY | KEY |
Predicate Information (identified by operation id):
2 - filter( EXISTS (SELECT 0 FROM "XIGNCMN"."INVOICEHEADERDISB" "INVOICEHEADERDISB","XIGNCMN"."INVOICELINEDISB"
"INVOICELINEDISB" WHERE "INVOICELINEDISB"."UNITOFMEASURECD"='USD' AND
"INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK" AND "INVOICEHEADERDISB"."PAYPK"=8135488395))
7 - access("INVOICELINEDISB"."UNITOFMEASURECD"='USD')
9 - filter("INVOICEHEADERDISB"."PAYPK"=8135488395)
10 - access("INVOICEHEADERDISB"."INVOICEPK"="INVOICELINEDISB"."INVOICEPK")
The sort unique at line 5 is surprising, I can't think of an obvious reason why it should appear unless the optimizer is trying to do something very clever to work around a problem we can't see (such as a statistics error with the hash partitioned indexe).
Assuming that the test would do better starting with invoiceheaderdisn.paypkl I have to ask if you have an index on INVOICELINEDISB(INVOICEPK).The optimizer's choice of driving table indeed looks odd. Could it be due to misleading statistics or plain bug or just a case of CBO preferring a non-partitioned table over partitioned table when deciding the driving table? I must admit this design does look odd as it appears INVOICEHEADERDISB is a parent table and INVOICELINEDISB is a child table but somehow the parent table has been partitioned (using hash partitioning, I assume) but the child table is not.
However, once CBO has decided the driving table, the SORT UNIQUE is not quite surprising. Assuming optimizer knows that there is a parent-child relationship between INVOICEHEADERDISB and INVOICELINEDISB table (based on INVOICEPK column), CBO needs to access only INVOICEPK and UNITOFMEASURECD columns fron the INVOICELINEDISB table in order to process the join. It uses index range scan on UNITOFMEASURECD table in order to get (part of) the necessary data and then accesses INVOICELINEDISB table to get the values of INVOICEPK column. Being a child table, it is possible that the driving row source will contain duplicate values for INVOICEPK column but not necessarily sorted. As CBO knows that outer table (i.e. INVOICEHEADERDISB) has a PK on INVOICEPK column, each row in driving row source will have either 1 or 0 rows matching from outer table. It appears that CBO "decides" that by eliminating the duplicate values of the INVOICEPK from driving row source, it can reduce the number of times the INVOICEHEADERDISB table is accessed.
Now I am not sure if CBO does all this (eliminating duplicates from driving row source) only because the outer table is partitioned.
Coming back to OP's original question, I believe OP will have to change the index definitions in order to avoid table access for this query. But there has to be a strong and logical argument to make this kind of change for just one query.
Hope this helps. -
Pagination query help needed for large table - force a different index
I'm using a slight modification of the pagination query from over at Ask Tom's: [http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html]
Mine looks like this when fetching the first 100 rows of all members with last name Smith, ordered by join date:
SELECT members.*
FROM members,
SELECT RID, rownum rnum
FROM
SELECT rowid as RID
FROM members
WHERE last_name = 'Smith'
ORDER BY joindate
WHERE rownum <= 100
WHERE rnum >= 1
and RID = members.rowidThe difference between this and the one at Ask Tom's is that my innermost query just returns the ROWID. Then in the outermost query we join the ROWIDs returned to the members table, after we have pruned the ROWIDs down to only the chunk of 100 we want. This makes it MUCH faster (verifiably) on our large tables, as it is able to use the index on the innermost query (well... read on).
The problem I have is this:
SELECT rowid as RID
FROM members
WHERE last_name = 'Smith'
ORDER BY joindateThis will use the index for the predicate column (last_name) instead of the unique index I have defined for the joindate column (joindate, sequence). (Verifiable with explain plan). It is much slower this way on a large table. So I can hint it using either of the following methods:
SELECT /*+ index(members, joindate_idx) */ rowid as RID
FROM members
WHERE last_name = 'Smith'
ORDER BY joindate
SELECT /*+ first_rows(100) */ rowid as RID
FROM members
WHERE last_name = 'Smith'
ORDER BY joindateEither way, it now uses the index of the ORDER BY column (joindate_idx), so now it is much faster as it does not have to do a sort (remember, VERY large table, millions of records). So that seems good. But now, on my outermost query, I join the rowid with the meaningful columns of data from the members table, as commented below:
SELECT members.* -- Select all data from members table
FROM members, -- members table added to FROM clause
SELECT RID, rownum rnum
FROM
SELECT /*+ index(members, joindate_idx) */ rowid as RID -- Hint is ignored now that I am joining in the outer query
FROM members
WHERE last_name = 'Smith'
ORDER BY joindate
WHERE rownum <= 100
WHERE rnum >= 1
and RID = members.rowid -- Merge the members table on the rowid we pulled from the inner queriesOnce I do this join, it goes back to using the predicate index (last_name) and has to perform the sort once it finds all matching values (which can be a lot in this table, there is high cardinality on some columns).
So my question is, in the full query above, is there any way I can get it to use the ORDER BY column for indexing to prevent it from having to do a sort? The join is what causes it to revert back to using the predicate index, even with hints. Remove the join and just return the ROWIDs for those 100 records and it flies, even on 10 million records.
It'd be great if there was some generic hint that could accomplish this, such that if we change the table/columns/indexes, we don't need to change the hint (the FIRST_ROWS hint is a good example of this, while the INDEX hint is the opposite), but any help would be appreciated. I can provide explain plans for any of the above if needed.
Thanks!Lakmal Rajapakse wrote:
OK here is an example to illustrate the advantage:
SQL> set autot traceonly
SQL> select * from (
2 select a.*, rownum x from
3 (
4 select a.* from aoswf.events a
5 order by EVENT_DATETIME
6 ) a
7 where rownum <= 1200
8 )
9 where x >= 1100
10 /
101 rows selected.
Execution Plan
Plan hash value: 3711662397
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1200 | 521K| 192 (0)| 00:00:03 |
|* 1 | VIEW | | 1200 | 521K| 192 (0)| 00:00:03 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | VIEW | | 1200 | 506K| 192 (0)| 00:00:03 |
| 4 | TABLE ACCESS BY INDEX ROWID| EVENTS | 253M| 34G| 192 (0)| 00:00:03 |
| 5 | INDEX FULL SCAN | EVEN_IDX02 | 1200 | | 2 (0)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter("X">=1100)
2 - filter(ROWNUM<=1200)
Statistics
0 recursive calls
0 db block gets
443 consistent gets
0 physical reads
0 redo size
25203 bytes sent via SQL*Net to client
281 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
101 rows processed
SQL>
SQL>
SQL> select * from aoswf.events a, (
2 select rid, rownum x from
3 (
4 select rowid rid from aoswf.events a
5 order by EVENT_DATETIME
6 ) a
7 where rownum <= 1200
8 ) b
9 where x >= 1100
10 and a.rowid = rid
11 /
101 rows selected.
Execution Plan
Plan hash value: 2308864810
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1200 | 201K| 261K (1)| 00:52:21 |
| 1 | NESTED LOOPS | | 1200 | 201K| 261K (1)| 00:52:21 |
|* 2 | VIEW | | 1200 | 30000 | 260K (1)| 00:52:06 |
|* 3 | COUNT STOPKEY | | | | | |
| 4 | VIEW | | 253M| 2895M| 260K (1)| 00:52:06 |
| 5 | INDEX FULL SCAN | EVEN_IDX02 | 253M| 4826M| 260K (1)| 00:52:06 |
| 6 | TABLE ACCESS BY USER ROWID| EVENTS | 1 | 147 | 1 (0)| 00:00:01 |
Predicate Information (identified by operation id):
2 - filter("X">=1100)
3 - filter(ROWNUM<=1200)
Statistics
8 recursive calls
0 db block gets
117 consistent gets
0 physical reads
0 redo size
27539 bytes sent via SQL*Net to client
281 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
101 rows processed
Lakmal (and OP),
Not sure what advantage you are trying to show here. But considering that we are talking about pagination query here and order of records is important, your 2 queries will not always generate output in same order. Here is the test case:
SQL> select * from v$version ;
BANNER
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
SQL> show parameter optimizer
NAME TYPE VALUE
optimizer_dynamic_sampling integer 2
optimizer_features_enable string 10.2.0.1
optimizer_index_caching integer 0
optimizer_index_cost_adj integer 100
optimizer_mode string ALL_ROWS
optimizer_secure_view_merging boolean TRUE
SQL> show parameter pga
NAME TYPE VALUE
pga_aggregate_target big integer 103M
SQL> create table t nologging as select * from all_objects where 1 = 2 ;
Table created.
SQL> create index t_idx on t(last_ddl_time) nologging ;
Index created.
SQL> insert /*+ APPEND */ into t (owner, object_name, object_id, created, last_ddl_time) select owner, object_name, object_id, created, sysdate - dbms_random.value(1, 100) from all_objects order by dbms_random.random;
40617 rows created.
SQL> commit ;
Commit complete.
SQL> exec dbms_stats.gather_table_stats(user, 'T', cascade=>true);
PL/SQL procedure successfully completed.
SQL> select object_id, object_name, created from t, (select rid, rownum rn from (select rowid rid from t order by created desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid ;
OBJECT_ID OBJECT_NAME CREATED
47686 ALL$OLAP2_JOIN_KEY_COLUMN_USES 28-JUL-2009 08:08:39
47672 ALL$OLAP2_CUBE_DIM_USES 28-JUL-2009 08:08:39
47681 ALL$OLAP2_CUBE_MEASURE_MAPS 28-JUL-2009 08:08:39
47682 ALL$OLAP2_FACT_LEVEL_USES 28-JUL-2009 08:08:39
47685 ALL$OLAP2_AGGREGATION_USES 28-JUL-2009 08:08:39
47692 ALL$OLAP2_CATALOGS 28-JUL-2009 08:08:39
47665 ALL$OLAPMR_FACTTBLKEYMAPS 28-JUL-2009 08:08:39
47688 ALL$OLAP2_DIM_LEVEL_ATTR_MAPS 28-JUL-2009 08:08:39
47689 ALL$OLAP2_DIM_LEVELS_KEYMAPS 28-JUL-2009 08:08:39
47669 ALL$OLAP9I2_HIER_DIMENSIONS 28-JUL-2009 08:08:39
47666 ALL$OLAP9I1_HIER_DIMENSIONS 28-JUL-2009 08:08:39
11 rows selected.
SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid ;
OBJECT_ID OBJECT_NAME LAST_DDL_TIME
11749 /b9fe5b99_OraRTStatementComman 06-FEB-2010 03:43:49
13133 oracle/jdbc/driver/OracleLog$3 06-FEB-2010 03:45:44
37534 com/sun/mail/smtp/SMTPMessage 06-FEB-2010 03:46:14
36145 /4e492b6f_SerProfileToClassErr 06-FEB-2010 03:11:09
26815 /7a628fb8_DefaultHSBChooserPan 06-FEB-2010 03:26:55
16695 /2940a364_RepIdDelegator_1_3 06-FEB-2010 03:38:17
36539 sun/io/ByteToCharMacHebrew 06-FEB-2010 03:28:57
14044 /d29b81e1_OldHeaders 06-FEB-2010 03:12:12
12920 /25f8f3a5_BasicSplitPaneUI 06-FEB-2010 03:11:06
42266 SI_GETCLRHSTGRFTR 06-FEB-2010 03:40:20
15752 /2f494dce_JDWPThreadReference 06-FEB-2010 03:09:31
11 rows selected.
SQL> select object_id, object_name, last_ddl_time from (select t1.*, rownum rn from (select * from t order by last_ddl_time desc) t1 where rownum <= 1200) where rn >= 1190 ;
OBJECT_ID OBJECT_NAME LAST_DDL_TIME
37534 com/sun/mail/smtp/SMTPMessage 06-FEB-2010 03:46:14
13133 oracle/jdbc/driver/OracleLog$3 06-FEB-2010 03:45:44
11749 /b9fe5b99_OraRTStatementComman 06-FEB-2010 03:43:49
42266 SI_GETCLRHSTGRFTR 06-FEB-2010 03:40:20
16695 /2940a364_RepIdDelegator_1_3 06-FEB-2010 03:38:17
36539 sun/io/ByteToCharMacHebrew 06-FEB-2010 03:28:57
26815 /7a628fb8_DefaultHSBChooserPan 06-FEB-2010 03:26:55
14044 /d29b81e1_OldHeaders 06-FEB-2010 03:12:12
36145 /4e492b6f_SerProfileToClassErr 06-FEB-2010 03:11:09
12920 /25f8f3a5_BasicSplitPaneUI 06-FEB-2010 03:11:06
15752 /2f494dce_JDWPThreadReference 06-FEB-2010 03:09:31
11 rows selected.
SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid order by last_ddl_time desc ;
OBJECT_ID OBJECT_NAME LAST_DDL_TIME
37534 com/sun/mail/smtp/SMTPMessage 06-FEB-2010 03:46:14
13133 oracle/jdbc/driver/OracleLog$3 06-FEB-2010 03:45:44
11749 /b9fe5b99_OraRTStatementComman 06-FEB-2010 03:43:49
42266 SI_GETCLRHSTGRFTR 06-FEB-2010 03:40:20
16695 /2940a364_RepIdDelegator_1_3 06-FEB-2010 03:38:17
36539 sun/io/ByteToCharMacHebrew 06-FEB-2010 03:28:57
26815 /7a628fb8_DefaultHSBChooserPan 06-FEB-2010 03:26:55
14044 /d29b81e1_OldHeaders 06-FEB-2010 03:12:12
36145 /4e492b6f_SerProfileToClassErr 06-FEB-2010 03:11:09
12920 /25f8f3a5_BasicSplitPaneUI 06-FEB-2010 03:11:06
15752 /2f494dce_JDWPThreadReference 06-FEB-2010 03:09:31
11 rows selected.
SQL> set autotrace traceonly
SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid order by last_ddl_time desc
2 ;
11 rows selected.
Execution Plan
Plan hash value: 44968669
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1200 | 91200 | 180 (2)| 00:00:03 |
| 1 | SORT ORDER BY | | 1200 | 91200 | 180 (2)| 00:00:03 |
|* 2 | HASH JOIN | | 1200 | 91200 | 179 (2)| 00:00:03 |
|* 3 | VIEW | | 1200 | 30000 | 98 (0)| 00:00:02 |
|* 4 | COUNT STOPKEY | | | | | |
| 5 | VIEW | | 40617 | 475K| 98 (0)| 00:00:02 |
| 6 | INDEX FULL SCAN DESCENDING| T_IDX | 40617 | 793K| 98 (0)| 00:00:02 |
| 7 | TABLE ACCESS FULL | T | 40617 | 2022K| 80 (2)| 00:00:01 |
Predicate Information (identified by operation id):
2 - access("T".ROWID="T1"."RID")
3 - filter("RN">=1190)
4 - filter(ROWNUM<=1200)
Statistics
1 recursive calls
0 db block gets
348 consistent gets
0 physical reads
0 redo size
1063 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
11 rows processed
SQL> select object_id, object_name, last_ddl_time from (select t1.*, rownum rn from (select * from t order by last_ddl_time desc) t1 where rownum <= 1200) where rn >= 1190 ;
11 rows selected.
Execution Plan
Plan hash value: 882605040
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1200 | 62400 | 80 (2)| 00:00:01 |
|* 1 | VIEW | | 1200 | 62400 | 80 (2)| 00:00:01 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | VIEW | | 40617 | 1546K| 80 (2)| 00:00:01 |
|* 4 | SORT ORDER BY STOPKEY| | 40617 | 2062K| 80 (2)| 00:00:01 |
| 5 | TABLE ACCESS FULL | T | 40617 | 2062K| 80 (2)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter("RN">=1190)
2 - filter(ROWNUM<=1200)
4 - filter(ROWNUM<=1200)
Statistics
0 recursive calls
0 db block gets
343 consistent gets
0 physical reads
0 redo size
1063 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
11 rows processed
SQL> select object_id, object_name, last_ddl_time from t, (select rid, rownum rn from (select rowid rid from t order by last_ddl_time desc) where rownum <= 1200) t1 where rn >= 1190 and t.rowid = t1.rid ;
11 rows selected.
Execution Plan
Plan hash value: 168880862
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1200 | 91200 | 179 (2)| 00:00:03 |
|* 1 | HASH JOIN | | 1200 | 91200 | 179 (2)| 00:00:03 |
|* 2 | VIEW | | 1200 | 30000 | 98 (0)| 00:00:02 |
|* 3 | COUNT STOPKEY | | | | | |
| 4 | VIEW | | 40617 | 475K| 98 (0)| 00:00:02 |
| 5 | INDEX FULL SCAN DESCENDING| T_IDX | 40617 | 793K| 98 (0)| 00:00:02 |
| 6 | TABLE ACCESS FULL | T | 40617 | 2022K| 80 (2)| 00:00:01 |
Predicate Information (identified by operation id):
1 - access("T".ROWID="T1"."RID")
2 - filter("RN">=1190)
3 - filter(ROWNUM<=1200)
Statistics
0 recursive calls
0 db block gets
349 consistent gets
0 physical reads
0 redo size
1063 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
11 rows processed
SQL> select object_id, object_name, last_ddl_time from (select t1.*, rownum rn from (select * from t order by last_ddl_time desc) t1 where rownum <= 1200) where rn >= 1190 order by last_ddl_time desc ;
11 rows selected.
Execution Plan
Plan hash value: 882605040
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1200 | 62400 | 80 (2)| 00:00:01 |
|* 1 | VIEW | | 1200 | 62400 | 80 (2)| 00:00:01 |
|* 2 | COUNT STOPKEY | | | | | |
| 3 | VIEW | | 40617 | 1546K| 80 (2)| 00:00:01 |
|* 4 | SORT ORDER BY STOPKEY| | 40617 | 2062K| 80 (2)| 00:00:01 |
| 5 | TABLE ACCESS FULL | T | 40617 | 2062K| 80 (2)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter("RN">=1190)
2 - filter(ROWNUM<=1200)
4 - filter(ROWNUM<=1200)
Statistics
175 recursive calls
0 db block gets
388 consistent gets
0 physical reads
0 redo size
1063 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
11 rows processed
SQL> set autotrace off
SQL> spool offAs you will see, the join query here has to have an ORDER BY clause at the end to ensure that records are correctly sorted. You can not rely on optimizer choosing NESTED LOOP join method and, as above example shows, when optimizer chooses HASH JOIN, oracle is free to return rows in no particular order.
The query that does not involve join always returns rows in the desired order. Adding an ORDER BY does add a step in the plan for the query using join but does not affect the other query. -
INDEX UNIQUE SCAN instead of INDEX FULL SCAN or TABLE ACCESS FULL
I have calculated statistics in all tables and indexes
I have a table and a view and when I put it
SELECT *
FROM TABLE_A A
INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID
WHERE (B.FK_ID_XXX = 1)
If I see the execution plan:
In TABLE_A make a
TABLE ACCESS BY INDEX ROWID
INDEX UNIQUE SCAN (FIELD_A_TABLE_A_PK)
Itâs OK. I NEED IT (INDEX UNIQUE SCAN)
But If I put
SELECT A.Field_1, A.Field_2, A.Field_3, A.Field_4
FROM TABLE_A A
INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID
WHERE (B.FK_ID_XXX = 1)
In table A make a TABLE ACCESS FULL.
Then If I put:
SELECT /*+ INDEX(A FIELD_A_TABLE_A_PK) */ A.Field_1, A.Field_2, A.Field_3, A.Field_4
FROM TABLE_A A
INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID
WHERE (B.FK_ID_XXX = 1)
If I see the execution plan:
In TABLE_A make a
TABLE ACCESS BY INDEX ROWID
INDEX UNIQUE SCAN (FIELD_A_TABLE_A_PK)
Itâs OK. I NEED IT (INDEX UNIQUE SCAN)
Finally, If I put other tables and views in the query (I NEED IT)
For example:
SELECT /*+ INDEX(A FIELD_A_TABLE_A_PK) */ A.Field_1, A.Field_2, A.Field_3, A.Field_4
FROM TABLE_A A
INNER JOIN VIEW_B B ON A.KEY_ID = B.PFK_KEY_ID
INNER JOIN TABLE_Câ¦.
LEFT JOIN VIEW_Dâ¦.
WHERE (B.FK_ID_XXX = 1)
If I see the execution plan:
In TABLE_A make a
TABLE ACCESS BY INDEX ROWID
INDEX FULL SCAN (FIELD_A_TABLE_A_PK)
I need INDEX UNIQUE SCAN instead of INDEX FULL SCAN or TABLE ACCESS FULL.
How can obtain it?
What happens???
Thanks!Notice the difference in cardinality between your two select statements:
SELECT STATEMENT, GOAL = ALL_ROWS Cost=5 Cardinality=1
SELECT STATEMENT, GOAL = ALL_ROWS Cost=10450 Cardinality=472161Apparently since the optimizer believed the first statement was going to return one row, it used an index. But in the second statement it believed it was going to return nearly the whole table (didn't you say it had around 500k rows?). Hence full table scan. -
Table access by index rowid taking more time
Hi All
I've a query like
update tab1
set col1 = ( select col2 from
tab2
where tab1.id = tab2.id) table 1 has arnd 10,000 rows
table 2 has arnd 1,700,000 rows and has a primay key on column id.
This query is taking around 20 secs to execute. I checked the xplan and most of time taken for table access by index rowid.
Could you please suggest what can be the reason for this. (Can it be the clustering factor or something else)
I checked the stats for the tab2, its just three days old.
Regards
Ashwani>
table 1 has arnd 10,000 rows
table 2 has arnd 1,700,000 rows and has a primay key on column id.
This query is taking around 20 secs to execute. I checked the xplan and most of time taken for table access by index rowid.
Could you please suggest what can be the reason for this. (Can it be the clustering factor or something else)
I checked the stats for the tab2, its just three days old.
>
If you checked the xplan why haven't you posted it so we can look at it? Then we could see what table is being accessed by index rowid. Presumably it is table 2 but we the plan would eliminate the need to make assumptions.
The clustering factor could be a factor. You haven't told us how table1 is being accessed. All rows are being updated so a full table scann is most likely but again the plan would actually show the access.
Did you query the dictionary to see what the clustering factor is? Post the results of that
SQL> select index_name, leaf_blocks, avg_leaf_blocks_per_key, avg_data_blocks_per_key, clustering_factor, distinct_keys
2 from dba_indexes
3 where owner = 'schema'
4 and index_name in ('index_b','index_a'); -
What are the tables are included for return delivery(T-Code - MIGO)? In that, particularly Invioce of purchase order has Tax code, after click the taxes button it displays condition types, amount and condition value. I need the table name for these taxes.
Hello Raja!
You can use Performance Assistant (F1 Key) and then Technical Information to find tables for certain screen fields.
If these fields correspond to structures instead of tables you can use tcode ST05 to find the tables accessed by the system while performing some actions in the system.
Apart from the help you need, please, try to post your thread in the right place in the Forum. This forum discusses ABAP Objects and i guess your problem is related to "ABAP Dictionary" Forum.
Regards, -
Excluding slow table access in a UNION ALL view
Hi,
I have a view which unions three tables together.
One component of the view requires a table scan, as 90% of the records are required.
This view is then used in another outer select where these records are actually not required.
So I tagged each component with a code and excluded that in the outer select. However it still appears to access the table.
Is there any way I can exclude a component of the UNION ALL or do I need to explicitly split them?
example:
SELECT * FROM (
SELECT 'A' Q, JANUARY F FROM ENORMOUS.TABLE WHERE KEY = 'Non Selective Key' UNION ALL
SELECT 'B' Q, 1 F FROM DUAL UNION ALL
SELECT 'C' Q, 1 F FROM DUAL
) A
WHERE Q = 'B'
When I run the query plan without the WHERE it performs the table scan
When I include the WHERE it still performs the table scan but with a FILTER NULL IS NOT NULL afterwards.
So it appears that it is doing the table scan regardless and then throwing the records away - is that correct?
Any thoughts appreciated. I would prefer not the split this view out if possible as it is used everywhere.In summary my question is: is The Oracle query planner smart enough to exclude a component from a load of stacked UNION ALL queries?
given this query:
CREATE VIEW TEST AS
SELECT Q, F
FROM
SELECT 'A' Q, JANUARY F FROM ENORMOUS.TABLE WHERE KEY = 'Non Selective Key' UNION ALL
SELECT 'B' Q, 1 F FROM DUAL UNION ALL
SELECT 'C' Q, 1 F FROM DUAL
) A;
-- 1. This one selects from all tables, including a table scan on the enormous table
SELECT * FROM TEST;
-- 2. This one selects from all tables, including a table scan on the enormous table
-- However the query plan has a FILTER after the table scan. Does it exclude this work?
SELECT * FROM TEST WHERE Q = 'B';When I run the query plan without the WHERE it performs the table scan
When I include the WHERE the query plan indicates it's doing the table scan but with a FILTER NULL IS NOT NULL afterwards.
So it appears that it is doing the table scan regardless and then throwing the records away - is that correct?
Any thoughts appreciated. I would prefer not the split this view out if possible as it is used everywhere.
Oracle version:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE 11.2.0.2.0 Production
TNS for 64-bit Windows: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production
Plan output for 1:
SELECT STATEMENT Optimizer Mode=ALL_ROWS (Cost=7166 Card=2 M Bytes=41 M)
1 VIEW (Cost=7166 Card=2 M Bytes=41 M)
2 1 UNION-ALL
3 2 TABLE ACCESS FULL PLANNING.BF_GEN_STATS_TRAN (Cost=7162 Card=2 M Bytes=72 M)
4 2 FAST DUAL (Cost=2 Card=1)
5 2 FAST DUAL (Cost=2 Card=1)
Plan output for 2:
SELECT STATEMENT Optimizer Mode=ALL_ROWS (Cost=2 Card=3 Bytes=48)
1 VIEW (Cost=2 Card=3 Bytes=48)
2 1 UNION-ALL
3 2 FILTER
4 3 TABLE ACCESS FULL PLANNING.BF_GEN_STATS_TRAN (Cost=7162 Card=2 M Bytes=72 M)
5 2 FAST DUAL (Cost=2 Card=1)
6 2 FILTER
7 6 FAST DUAL (Cost=2 Card=1) -
Hi all,
could someone please advise me tool for definition of needed index? In other words, I got query with "table access full", because one of tables doesn't have any indexes, so I should know what index would be the best to create. I don't say that "table access full" is always evil, but I guess index can possibly improve performance.best indexes include the most frequently used columns in the ON (Join) and WHERE clauses. With no index, it can only do a FTS.
create an index in a test environment
set autotrace traceonly explain;
select.... from table where <indexed col> etc..
set autotrace off -- to turn it off...
--REPEAT this sequence until you have the plan you expect
Using this autotrace does not actually execute the query (no rows retrieved). Review the output looking for ACCESS method vs. FILTER method -
Hi,
we are in a cleaning process. Althoug nobody gets hurt by unnused customer tables, the customer wants to know about tables that are nort used.
One approach is a where-used-list. OK, done.
Another approach is to analyze table access statistics. AFAIK the database collects statistics from database accesses. From those statistics the system gains information to optimize table access.
Now my question: Where can I find (programatrically or via transaction/report) information about table access?
TIA,
regards,
ClemensU have the list of custom related tables. Goto SE11 & using the custom table check where-used-list. It displays where all the table has been used. If the table has not been used anywhere or else not related at all to a program which is not needed, these all tables can be eliminated from the system.
-
I am using WITH query to reduce the scanning the teacher table thrice for the below query
xe > with q as
2 (select teacher_id,subject_1,subject_2,subject_3 from teacher
3 )
4 select teacher_id,subject_1 from q
5 union all
6 select teacher_id,subject_2 from q
7 union all
8 select teacher_id,subject_3 from q
9 /
However, the execution plan shows that the table was scanned for twice.
Execution Plan
Plan hash value: 91048842
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 6 | 180 | 6 (67)| 00:00:01 |
| 1 | UNION-ALL | | | | | |
| 2 | TABLE ACCESS FULL| TEACHER | 2 | 60 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| TEACHER | 2 | 60 | 2 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| TEACHER | 2 | 60 | 2 (0)| 00:00:01 |
Note
- dynamic sampling used for this statement (level=2)
Statistics
10 recursive calls
0 db block gets
22 consistent gets
0 physical reads
0 redo size
594 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6 rows processed
Why the table was scanned thrice?
Thanks for your time..Hi,
A SQL query describes the result set you want; it does not show how the system gets those results. Don't expect how the query code looks to have much to do with what the system will do. For example, the fact that the code only says "teacher" 1 time doesn't mean that the teacher table will only be scanned 1 time.
Try
SELECT teacher_id, subject
FROM teacher
UNPIVOT ( subject
FOR subject_num IN ( subject_1 AS 1
, subject_2 AS 2
, subject_3 AS 3 -
Why Java doesn't allow to reduce the accessibility of a method du
Why Java compiler does not allow to reduce the accessibility of a method during inheritance?
( Eg; If the base class has a public method and if that method is overridden in child class but
with defuault access, it gives compile error)
Supposed answer:
Because in the runtime, it cannot check the access modifier.
Suppose A is the base class. It has a method fun() as public.
B is the derived class of A.
Suppose in some other class (say C) there is a method myFun() which takes A as parameter and
calls the fun() method of A. So that method can take B
also as parameter (As it is derived from A).
So if the fun() method's accessibility is reduced in B, whether "that can
be called in C or not" is not known. that is why compiler does not
allow the reduce the accessibility of a method during inheritance.
Member variables do not have this problem as they can be checked at
compile time.
Is this explanation correct?You can give private access, sort of... you could fake it, if the goal is to prevent someone from doing what the method does. Of course, they could (as long as A isn't abstract) create their own A and do whatever they want.
class A {
public void doThis() {
class B extends A {
public void doThis() {
// explicitly do nothing
}But I think generally, this shouldn't be a problem. I'm not sure if it's something that is common for creating an API to subclass another class to hide the superclass's methods. Usually you are adding functionality to a subclass that is for more specific things then the superclass supports. I mention creating an API because if it's just for some application class, then you are writing it, so use or not use the methods as you want. It's APIs for library type classes that other people would use, and if you are extending the library, and really need people not to call methods for some reason, document it. Maybe a good place for an assertion? -
Error during table access in SRM portal
Hello Experts,
Recently we have upgraded the R/3 System 4.6C to ECC 6.0. We are trying to change the quantity of PO and order again in SRM 7.0 portal , but it is throwing an error 'Error during table access'. This happens only when we try to change the ordered PO and only after the R3 system is upgraded.I have checked across SDN forum before posting, but was not able to get relevant information.
Let me know if any configuration at the basis/functional level or any BADI needs to be checked, or if any OSS notes is there for ECC 6.0.
I checked two of them and it was not relevant to ECC.
Could you please help me in solving the issue?
Thanks in Advance,
M M Jaffer.Hi Mathweus,
the namespace seems to be standard SAP name space with pre delivered content. So i think you can not regenerate the proxy in the same namespace. you need to copy the data type, message type and service interface to custom SWCV and namespace and then regenerate the proxy.
regards,
Harish -
How improve performance on access path TABLE ACCESS BY INDEX ROWID ?
I have table MOVEMENT with about 26millions entries,
select rowid from movement xxx
where
xxx.sTransType > 0
AND xxx.sDevice < 1000
AND xxx.sDevice >= 0
AND (bitand(xxx.sSaleFlag,1) = 0 AND bitand(xxx.sSaleFlag,4) = 0)
AND xxx.sArtClassRef < 100
and xxx.tActionTime BETWEEN TO_DATE('13-05-2011 08:08:34', 'dd-mm-yyyy hh24:mi:ss') AND to_date('13-05-2011 14:08:34', 'dd-mm-yyyy hh24:mi:ss') ;
PLAN_TABLE_OUTPUT
Plan hash value: 679628763
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 34 | 10102 (1)| 00:02:02 |
|* 1 | TABLE ACCESS BY INDEX ROWID| MOVEMENT | 1 | 34 | 10102 (1)| 00:02:02 |
|* 2 | INDEX RANGE SCAN | MOVATIME_IX | 18489 | | 51 (0)| 00:00:01 |
Predicate Information (identified by operation id):
1 - filter("XXX"."SARTCLASSREF"<100 AND BITAND("XXX"."SSALEFLAG",1)=0 AND
BITAND("XXX"."SSALEFLAG",4)=0 AND "XXX"."STRANSTYPE">0 AND "XXX"."SDEVICE"<1000
AND "XXX"."SDEVICE">=0)
2 - access("XXX"."TACTIONTIME">=TO_DATE('2011-05-13 08:08:34', 'yyyy-mm-dd
hh24:mi:ss') AND "XXX"."TACTIONTIME"<=TO_DATE('2011-05-13 14:08:34', 'yyyy-mm-dd
hh24:mi:ss'))
there is index on tActionTime - MOVATIME_IX
This query returns 12203 rows, so I would anticipate this number in plan table in row with id 1 and column Rows
Final question if it is possible to optimize this query and what are the next steps to do it?
Thanks.>
I thought that access path via ROWID's is the fastest way to get row
>
It is the fastest way to get the row - FROM THE TABLE.
But the ROWIDs have to be gotten from the index. That is what the INDEX RANGE SCAN is doing. It is getting the ROWIDs needed and then the TABLE ACCESS BY INDEX ROWID is getting the rows.
>
I'am still confused with COST values, TABLE ACCESS BY INDEX ROWID has 200times higher cost than INDEX RANGE SCAN,
>
The index entries for a range scan are in order so they are very compact. The actual rows might be all over the place.
Have you ever you a library? Not the online ones - I mean the old-fashioned kind that actually has books printed on paper?
If the librarian asks you, her helper, to go get all books whose title begins with the letter 'B' how would you do it?
You could go back to the stacks and look at every book on every shelf for books with titles' starting with 'B'. That is the same as a FULL TABLE SCAN.
Or you could go to the card catalog, pull out the drawer (or drawers) that has 'B' on the label and look at the information on the card. Part of that information is the location of the actual book: section, stack; that is similar to the ROWID.
The card catalog might get you to the right stack of books; then you have to search the stack sequentially to look for the book by name.
A ROWID will get Oracle to the right block but then it has to find the right row.
So the cost of getting ROWIDs from an index using a RANGE SCAN (where values are scanned in order) is a lot cheaper than actually getting the rows. The first two index entries needed might be right next to each other in order but the rows themselves might be far apart on the disk. -
URGENT NEED HELP : JOURNALING TABLES AND TRIGGERS GENERATION
Hi
I need generate journaling tables for any tables to audit the update, delete statements executed for the users. I captured an existant schema, then and I change the derfiniton of the target tables, setting the value of Journaling to "Server".
But, when I generate the DDL statements, the triggers of the journaling tables don't appears in the sql file.
¿What is the error?
I thing that Designer generates the triggers and the journal tables, ¿It's true?
Thanks in advance.
XaviYou have to use the "Generate Table API" menu option. This will generate the "journalling" triggers.
HTH
Roel -
Have CS5 and CS6. Need to reduce size of file from 6Mb to 2 Mb for contest purposes without losing original
Just save the document to a new jpeg file name using a lower quality setting or re-size the image down in size the save a high quality smaller new jpeg image.
Maybe you are looking for
-
How to store multiple records for one master reocrd using sequnce
dear, my question is in one form i have master block f and detail block. my question is i created one sequence and assign to master table. but i dont know how to assign that sequence to multiple record in detail table for that particular master recor
-
I have a Canon camera that has wifi. Before the OIS 7 upgrade, I could upoad phots from my camera to either the iphone, or ipad wirelessly. Since the upgrade, i cannot. Anyone found a soluti on. I have tried resetting the settings on the camera t
-
PR transfer from R/3 to SRM with same number
We are transfering R/3 PR's to EBP. We want keep Number of Shopping card same as PR number in R/3 It is always picks up Internal Number range for the shopping card in SRM. We have only kept external number assignment for shopping cart transaction typ
-
Hi, Pc worked properly, and when closing the lid I've heard clicking noise. Next day I got a black screen, I can hear a noise from inside that components work ( not quite sure which one), and there is no any indicator light except for the one on star
-
How to create web site using STRUTS frame work
Hi, I know how to create web pages using JSP & Servlets.But now i have to create Matrimonial web site using STRUTS frame work.Plz any one guide for me... Thank U....