query tuning [message #382959] |
Mon, 26 January 2009 14:53 |
varunvir
Messages: 389 Registered: November 2007
|
Senior Member |
|
|
Hi Experts,
Following query is using lot of CPU:-
SELECT qv.friendly_name AS VALUE
FROM bv_category c,
bv_content_ref cr,
bv_ep_qual_value qv,
bv_ep_uprof_qval uq
WHERE c.content_type = 315
AND c.NAME = 'GenericRole'
AND c.store_id IN (SELECT s.store_id
FROM bv_store s
WHERE s.store_name = 'CLIFT')
AND c.oid = cr.parent_oid
AND qv.oid = cr.oid
AND qv.status = 1
AND qv.deleted = 0
AND uq.user_id = 10082863
AND uq.qvid = qv.oid
The explain plan for the query is:-
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=21 Card=1 Bytes=81
)
1 0 NESTED LOOPS (Cost=21 Card=1 Bytes=81)
2 1 HASH JOIN (Cost=21 Card=108 Bytes=7560)
3 2 MERGE JOIN (CARTESIAN) (Cost=8 Card=108 Bytes=4752)
4 3 NESTED LOOPS (Cost=4 Card=2 Bytes=66)
5 4 TABLE ACCESS (BY INDEX ROWID) OF 'BV_STORE' (TABLE
) (Cost=1 Card=1 Bytes=9)
6 5 INDEX (UNIQUE SCAN) OF 'BV_STORE_NAME_INDEX' (IN
DEX (UNIQUE)) (Cost=0 Card=1)
7 4 TABLE ACCESS (BY INDEX ROWID) OF 'BV_CATEGORY' (TABLE) (Cost=3 Card=2 Bytes=48)
8 7 INDEX (RANGE SCAN) OF 'BV_CATEGORY_KEY_IDX' (IND
EX (UNIQUE)) (Cost=2 Card=2)
9 3 BUFFER (SORT) (Cost=5 Card=57 Bytes=627)
10 9 INDEX (RANGE SCAN) OF 'BV_EP_UPROF_QVAL_PK' (INDEX
(UNIQUE)) (Cost=2 Card=57 Bytes=627)
11 2 TABLE ACCESS (FULL) OF 'BV_EP_QUAL_VALUE' (TABLE) (Cos
t=12 Card=1147 Bytes=29822)
12 1 INDEX (UNIQUE SCAN) OF 'BV_CONTENT_REF_PK' (INDEX (UNIQU
E)) (Cost=0 Card=1 Bytes=11)
The rowcounts for tables involved are:-
select count(*) from bv_category--44181
select count(*) from bv_content_ref--56472
select count(*) from bv_ep_qual_value--2294
select count(*) from bv_ep_uprof_qval--5238265
What can I do to reduce the cpu utilization from this query.
|
|
|
Re: query tuning [message #382961 is a reply to message #382959] |
Mon, 26 January 2009 14:59 |
|
BlackSwan
Messages: 26766 Registered: January 2009 Location: SoCal
|
Senior Member |
|
|
>What can I do to reduce the cpu utilization from this query.
SELECT qv.friendly_name AS VALUE
FROM bv_category c,
bv_content_ref cr,
bv_ep_qual_value qv,
bv_ep_uprof_qval uq
Eliminate C, CR, & UQ tables out of the FROM clause; because they contribute no data to SELECT clause.
Subordinate them into the WHERE clause.
Post results from each of these queries:
SELECT count(*) FROM bv_ep_qual_value qv WHERE qv.status = 1;
SELECT count(*) FROM bv_ep_qual_value qv WHERE qv.deleted = 0;
Do qv.status & qv.deleted have indexes on them?
[Updated on: Mon, 26 January 2009 15:18] Report message to a moderator
|
|
|
Re: query tuning [message #382963 is a reply to message #382961] |
Mon, 26 January 2009 15:22 |
varunvir
Messages: 389 Registered: November 2007
|
Senior Member |
|
|
Thanks Blackswan for you help.
I am posting the results for following queries:-
SELECT count(*) FROM bv_ep_qual_value qv WHERE qv.status = 1;---2294
SELECT count(*) FROM bv_ep_qual_value qv WHERE qv.deleted = 0;--1983
Please give me some idea about:-
Eliminate C, CR, & UQ tables out of the FROM clause; because they contribute no data to SELECT clause.
Subordinate them into the WHERE clause.
How can we subordinate them into where clause.
Regards,
Varun Punj
|
|
|
|
Re: query tuning [message #382967 is a reply to message #382964] |
Mon, 26 January 2009 15:45 |
varunvir
Messages: 389 Registered: November 2007
|
Senior Member |
|
|
Hi BlackSwan,
Sorry for being dumb but I still could not understand:-
How can we subordinate them into where clause.
by EXISTS or IN as part of the WHERE clause
Regards,
Varun Punj,
|
|
|
|
Re: query tuning [message #383239 is a reply to message #382968] |
Tue, 27 January 2009 20:45 |
rleishman
Messages: 3728 Registered: October 2005 Location: Melbourne, Australia
|
Senior Member |
|
|
Your optimiser thinks that there are 57 rows in bv_ep_uprof_qval that have
AND qv.status = 1
AND qv.deleted = 0
Is that true? Or is there a lot more?
If there is a lot more, gather statistics on this table with DBMS_STATS.GATHER_TABLE_STATS().
This should avoid the CARTESIAN JOIN, which is probably the source of your problem.
Ross Leishman
|
|
|
Re: query tuning [message #383391 is a reply to message #383239] |
Wed, 28 January 2009 11:38 |
varunvir
Messages: 389 Registered: November 2007
|
Senior Member |
|
|
Thanks for replying Ross..
AND qv.status = 1---2294
AND qv.deleted = 0 ---1983
How did you come to know that my optimizer thinks that there
are 57 rows that have
AND qv.status = 1
AND qv.deleted = 0
Regards,
Varun Punj
|
|
|
Re: query tuning [message #383430 is a reply to message #383391] |
Wed, 28 January 2009 20:23 |
rleishman
Messages: 3728 Registered: October 2005 Location: Melbourne, Australia
|
Senior Member |
|
|
Quote: | 10 9 INDEX (RANGE SCAN) OF 'BV_EP_UPROF_QVAL_PK' (INDEX
(UNIQUE)) (Cost=2 Card=57 Bytes=627)
|
I'm not interested in how many rows match each predicate. How many match BOTH?
And while you're at it, how many rows in BV_CATEGORY match
AND c.store_id IN (SELECT s.store_id
FROM bv_store s
WHERE s.store_name = 'CLIFT')
Ross Leishman
|
|
|
Re: query tuning [message #383437 is a reply to message #383430] |
Wed, 28 January 2009 21:30 |
varunvir
Messages: 389 Registered: November 2007
|
Senior Member |
|
|
Hi Ross,
select count(*) from bv_ep_qual_value where status=1 and deleted=0--1983
select * from bv_category where store_id in(SELECT s.store_id
FROM bv_store s WHERE s.store_name = 'CLIFT')--254
Regards,
Varun Punj,
|
|
|
|
Re: query tuning [message #383772 is a reply to message #383440] |
Fri, 30 January 2009 01:08 |
rleishman
Messages: 3728 Registered: October 2005 Location: Melbourne, Australia
|
Senior Member |
|
|
OK. So the following cartesian join:
3 2 MERGE JOIN (CARTESIAN) (Cost=8 Card=108 Bytes=4752)
that Oracle thinks will return 108 rows, actually reurns 1983 x 254 = 503,682 rows. That's a bit different.
- Gather statistics on all tables using DBMS_STATS.GATHER_TABLE_STATS.
- Make sure you have an index on bv_content_ref(cr.parent_oid)
- Make sure you have an index on bv_content_ref(cr.oid)
- Make sure you have an index on bv_ep_uprof_qval(user_id)
- Make sure you have an index on bv_ep_uprof_qval(qvid)
- Make sure you have an index on bv_ep_qual_value(oid)
- Make sure you have an index on bv_category(oid)
Ross Leishman
|
|
|
|
Re: query tuning [message #383817 is a reply to message #383774] |
Fri, 30 January 2009 06:41 |
rleishman
Messages: 3728 Registered: October 2005 Location: Melbourne, Australia
|
Senior Member |
|
|
BlackSwan wrote on Fri, 30 January 2009 18:24 | Why the difference?
|
Could be bad statistics.
But it just may be bad luck:
- The estimate of rows from bv_category (2 instead of 254) is based on a foreign key IN sub-query. At best, Oracle can go on the mean cardinality of that foreign key. However if the mean cardinality is 2, then a single sample of 254 is fairly skewed. This degree of skewness is possible, but so are bad/no statistics.
I made a mistake on the other one. I should have asked how many rows matched:
AND uq.user_id = 10082863
because that is the other side of the cartesian merge. But it's probably immaterial - the first example has shown the optimiser to be way out. If it thinks it is getting one or two rows, it is happy to cartesian join to a larger row source. 254 is a different story.
Quote: | - Gather statistics on all tables using DBMS_STATS.GATHER_TABLE_STATS.
- Make sure you have an index on bv_content_ref(cr.parent_oid)
- Make sure you have an index on bv_content_ref(cr.oid)
- Make sure you have an index on bv_ep_uprof_qval(user_id)
- Make sure you have an index on bv_ep_uprof_qval(qvid)
- Make sure you have an index on bv_ep_qual_value(oid)
- Make sure you have an index on bv_category(oid)
|
And also (possibly most importantly):
- Make sure you have an index on bv_category(content_type,name, store_id) in any order
|
|
|
Re: query tuning [message #383865 is a reply to message #383817] |
Fri, 30 January 2009 16:24 |
varunvir
Messages: 389 Registered: November 2007
|
Senior Member |
|
|
Thanks Ross and Blackswan for all your help,
I gathered the statistics on all tables and it worked.
Ross,
I have few basic question now to make my concepts solid:-
I have following indexes on the tables:-
There is already concatenate index on(name,content_type,parent_oid,store_oid) in bv_category;
there is concatenate index on (user_id,qid,qvid)in bv_ep_uprof_qval
There is index on OID in bv_ep_qual_value.
there is index on oid and parent oid in bv_content_ref
As you told me to create separate index on bv_ep_uprof_qval like this:-
Make sure you have an index on bv_ep_uprof_qval(user_id)
Make sure you have an index on bv_ep_uprof_qval(qvid)
So I have concatenated index on these two columns but requirement was to use separate index.So it means Oracle
automatically use concatenated indexes as separate index when
required.Is It right?
2,Do I need to gather statisics on these tables everyday
or Oracle wiil take care of it.
3,The new explain plan is:-
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=11 Card=1 Bytes=89
)
1 0 NESTED LOOPS (Cost=11 Card=1 Bytes=89)
2 1 NESTED LOOPS (Cost=9 Card=1 Bytes=76)
3 2 NESTED LOOPS (Cost=8 Card=1 Bytes=49)
4 3 NESTED LOOPS (Cost=4 Card=1 Bytes=37)
5 4 TABLE ACCESS (BY INDEX ROWID) OF 'BV_STORE' (TABLE
) (Cost=1 Card=1 Bytes=9)
6 5 INDEX (UNIQUE SCAN) OF 'BV_STORE_NAME_INDEX' (IN
DEX (UNIQUE)) (Cost=0 Card=1)
7 4 TABLE ACCESS (BY INDEX ROWID) OF 'BV_CATEGORY' (TA
BLE) (Cost=3 Card=1 Bytes=28)
8 7 INDEX (RANGE SCAN) OF 'BV_CATEGORY_KEY_IDX' (IND
EX (UNIQUE)) (Cost=2 Card=1)
9 3 TABLE ACCESS (BY INDEX ROWID) OF 'BV_CONTENT_REF' (T
ABLE) (Cost=4 Card=1 Bytes=12)
10 9 INDEX (RANGE SCAN) OF 'BV_CNTRF_IDX' (INDEX) (Cost
=2 Card=25)
11 2 TABLE ACCESS (BY INDEX ROWID) OF 'BV_EP_QUAL_VALUE' (T
ABLE) (Cost=1 Card=1 Bytes=27)
12 11 INDEX (UNIQUE SCAN) OF 'BV_EP_QUAL_VALUE_PK' (INDEX
(UNIQUE)) (Cost=0 Card=1)
13 1 INDEX (RANGE SCAN) OF 'BV_EP_UPROF_QVAL_PK' (INDEX (UNIQ
UE)) (Cost=2 Card=1 Bytes=13)
There is lot of reduction in cost,card,bytes.
On what factors CPU is dependent out of these three.
Please provide me some detailed document(If you have any)to
understand Explain Plan.
Once again thanks a lot for all you help.
Regards,
Varun Punj
|
|
|
Re: query tuning [message #383871 is a reply to message #383865] |
Fri, 30 January 2009 16:49 |
rleishman
Messages: 3728 Registered: October 2005 Location: Melbourne, Australia
|
Senior Member |
|
|
Having a concatenated index means you do not need to have a separate index on the first column of the concatenated index. Oracle can use the LEADING columns of an index just like it uses the whole index.
I asked about the other indexes because it is a good rule of thumb to index:
- Every join condition
- Every selective filter
Oracle 10g has a feature to automatically gather statistics. I think it is switched on by default, but you would need to check - someone may have switched it off.
If statistics are not automatically gathered, you need to do it yourself whenever the distribution of data changes significantly in the table/index (ie. more than a few percent)
Take a look at the Sticky thread at the top of this forum. There are several good resources there including the Oracle Performance Tuning Manual (which has a chapter devoted to Explain Plan) and my own guide on this site: http://www.orafaq.com/tuningguide
Your problem - no/bad statistics - is number one in the "quick fix" guide on that link.
Ross Leishman
|
|
|