Poorly performing SQL query [message #286312] |
Fri, 07 December 2007 02:46 |
rdoggart
Messages: 10 Registered: December 2007 Location: Belfast
|
Junior Member |
|
|
Hi All,
I have a problem with a customer database and performance. I have ran statspack and identified the worst performing SQL statement, but have run out of ideas on how to get the SQL to perform better. The query was not a problem a month ago, but has only recently started to cause problems. I do not have an old explain plan to compare it to. The query is from an application and so cannot be changed. Why are we doing so many ‘DB File Sequential Reads’ when the hash join is doing full table accesses ? And why am I reading 20,000+ blocks to get two rows.
TKprof output:
select * from lgncc_commoncaseview where
clientid = :b1 and
clienttype = :b2 and (1=1)
union
select * from lgncc_commoncaseview where
xref1 = :b3 and
objecttype = :b4 and (1=1)
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 4.49 34.89 1787 21664 0 2
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 4.49 34.90 1787 21664 0 2
Misses in library cache during parse: 0
Optimizer goal: CHOOSE
Parsing user id: 64
Rows Row Source Operation
------- ---------------------------------------------------
2 SORT UNIQUE
2 UNION-ALL
1 NESTED LOOPS
1 HASH JOIN
4 TABLE ACCESS BY INDEX ROWID OBJ#(35867)
4 INDEX RANGE SCAN OBJ#(38739) (object id 38739)
117901 HASH JOIN OUTER
117901 TABLE ACCESS FULL OBJ#(35878) (lgncc_enquiry)
1475502 TABLE ACCESS FULL OBJ#(35880) (lgncc_enquiryrelation)
1 TABLE ACCESS BY INDEX ROWID OBJ#(35873)
1 INDEX UNIQUE SCAN OBJ#(35874) (object id 35874)
1 NESTED LOOPS OUTER
1 NESTED LOOPS OUTER
1 NESTED LOOPS
1 TABLE ACCESS BY INDEX ROWID OBJ#(35878)
1 INDEX RANGE SCAN OBJ#(38738) (object id 38738)
1 TABLE ACCESS BY INDEX ROWID OBJ#(35873)
1 INDEX UNIQUE SCAN OBJ#(35874) (object id 35874)
1 INDEX RANGE SCAN OBJ#(38516) (object id 38516)
1 TABLE ACCESS BY INDEX ROWID OBJ#(35867)
1 INDEX UNIQUE SCAN OBJ#(35868) (object id 35868)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 2 0.00 0.00
db file sequential read 1382 0.17 16.42
db file scattered read 175 0.10 3.45
latch free 6 0.01 0.01
buffer busy waits 1137 0.08 11.15
SQL*Net more data to client 1 0.00 0.00
SQL*Net message from client 2 6.89 6.89
Lgncc_CommonCaseview Definition
SELECT
-- [ID]
ENQUIRY.ID AS REFERENCE,
0 AS TYPE,
-- [DESCRIPTION]
ENQUIRY.TITLE AS LINE1,
TYPE.NAME AS LINE2,
-- [CASE]
ENQUIRY.CASEID AS CASEID,
ENQUIRY.CASEREF AS RELATEDCASE,
ENQUIRY.ENQUIRYTYPE AS ENQUIRYTYPE,
ENQUIRY.OBJECTTYPE AS OBJECTTYPE,
ENQUIRY.XREF1 AS XREF1,
ENQUIRY.XREF2 AS XREF2,
ENQUIRY.XREF3 AS XREF3,
ENQUIRY.OBJECTDESC AS OBJECTDESC,
-- [INTERACTION]
INT.CLIENTTYPE AS CLIENTTYPE,
INT.CLIENTID AS CLIENTID,
INT.CLIENTNAME AS CLIENTNAME,
INT.LOGID AS INTERACTIONID,
INT.INTREF AS INTERACTIONREF,
INT.VERIFIED AS INTERACTIONVERIFIED,
nvl(INT.INITCHANNEL, -1) AS INTERACTIONCHANNEL,
INT.REFERENCE AS INTERACTIONREFERENCE,
INT.STARTTIME AS INTERACTIONDATE,
-- [STATUS]
NULL AS TARGETDATE,
ENQUIRY.STATUS AS STATUS,
-- [AUDIT]
ENQUIRY.CREATIONDATE AS CREATIONDATE,
ENQUIRY.SOURCEID AS CREATEDBY,
ENQUIRY.CREATIONDATE AS MODIFIEDDATE,
NULL AS MODIFIEDBY
FROM
LGNCC_ENQUIRY ENQUIRY
INNER JOIN LGNCC_ENQUIRYTYPE TYPE ON
ENQUIRY.ENQUIRYTYPE = TYPE.ID
LEFT OUTER JOIN LGNCC_ENQUIRYRELATION REL ON
ENQUIRY.ID = REL.ENQUIRYID AND REL.RELATION = 1
LEFT OUTER JOIN LGNCC_INTLOGHDR INT ON
INT.LOGID = REL.INTERACTIONID
WHERE
ENQUIRY.CASEREF IS NOT NULL AND ENQUIRY.DELETEDDATE IS NULL
Ronnie Doggart
|
|
|
|
|
|
|
Re: Poorly performing SQL query [message #286594 is a reply to message #286312] |
Sat, 08 December 2007 13:59 |
mchadder
Messages: 224 Registered: May 2005 Location: UK
|
Senior Member |
|
|
Sounds like the old "outer joins are slow" argument, just like the "IN is faster than EXISTS" (or vice versa) or the "views are slow" argument... Plus, of course, the OP did actually post the view definition...
Anyway, why do you think that this shouldn't incur sequential reads? I can see full scan IO here, as part of the HASH JOIN, so sequential reads are definitely on the cards....
Unfortunately, there's not enough information here to show exactly why Oracle is choosing a HASH JOIN with full scans, but you do have unpredicated selects in that UNION on lgncc_enquiry and lgncc_enquiryrelation for the simple reason that
clientid = :b1 and
clienttype = :b2
come from LGNCC_INTLOGHDR, whereas
xref1 = :b3 and
objecttype = :b4
come from LGNCC_ENQUIRY, hence why you end up with full scans, if the indexing strategy does not allow any other kind of access path when predicating on these columns.
It would be necessary to see what the index structure is on LGNCC_INTLOGHDR, plus number of rows, whether histograms exist, what the settings of various optimiser parameters are, etc. etc.
to truly work out what is going on, such as whether bind variable peeking has occurred here and is skewing your plan for this particular instance of the query.
What is the plan like for just running the first part of the query?, i.e.
select * from lgncc_commoncaseview where
clientid = :b1 and
clienttype = :b2
Does it match that what is shown in the tkprof output (with the possible changes due to environmental differences)? Also, post the plan when not using bind variables, to see if peeking has had an effect.
Regards
|
|
|
Re: Poorly performing SQL query [message #286656 is a reply to message #286312] |
Sun, 09 December 2007 07:48 |
michael_bialik
Messages: 621 Registered: July 2006
|
Senior Member |
|
|
Don't be so angry, guys...
I intended to say that "in that particular case outer join may cause bad performance" because of following:
select * from lgncc_commoncaseview where
clientid = :b1 and
clienttype = :b2
If you look at view definition then you will see that both clientid and clienttype columns are coming from LGNCC_INTLOGHDR table (which is accessed by the outer join).
So IMHO (because outer join enforces join order) the optimizer performs following:
1. Full table scan on lgncc_enquiry table (because there is no and conditions in WHERE referencing that table) and store it in hash area
2. Full table scan on LGNCC_INTLOGHDR (probably there is no index on clientid and clienttype columns or optimizer thinks that full table scan is better/faster)
In that case I would like:
1. Verify an index existance on clientid and clienttype columns of LGNCC_INTLOGHDR table (and create one if needed).
2. Exchage OUTER join for a regular one when accessing LGNCC_INTLOGHDR table.
In my opinion - the OUTER join is not needed here, because there is an explicit value is given in WHERE for 2 columns accessed in outer joined table ( clientid and clienttype).
Michael
|
|
|
Re: Poorly performing SQL query [message #286875 is a reply to message #286312] |
Mon, 10 December 2007 05:47 |
rdoggart
Messages: 10 Registered: December 2007 Location: Belfast
|
Junior Member |
|
|
Guys,
Here is the plan when run with no bind variables:
select * from lgncc_commoncaseview where
clientid = '101000031874' and
clienttype = 1 and
(1=1)
union
select * from lgncc_commoncaseview where
xref1 = '101000031874' and
objecttype = 'C1' and
(1=1)
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.06 0.06 0 9 0 0
Execute 1 0.00 0.01 0 0 0 0
Fetch 2 5.75 9.62 16101 21927 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 5.81 9.69 16101 21936 0 1
Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 64
Rows Row Source Operation
------- ---------------------------------------------------
1 SORT UNIQUE
2 UNION-ALL
1 NESTED LOOPS
1 HASH JOIN
4 TABLE ACCESS BY INDEX ROWID OBJ#(35867)
4 INDEX RANGE SCAN OBJ#(38739) (object id 38739)
118984 HASH JOIN OUTER
118984 TABLE ACCESS FULL OBJ#(35878)
1488680 TABLE ACCESS FULL OBJ#(35880)
1 TABLE ACCESS BY INDEX ROWID OBJ#(35873)
1 INDEX UNIQUE SCAN OBJ#(35874) (object id 35874)
1 NESTED LOOPS OUTER
1 NESTED LOOPS OUTER
1 NESTED LOOPS
1 TABLE ACCESS BY INDEX ROWID OBJ#(35878)
1 INDEX RANGE SCAN OBJ#(38738) (object id 38738)
1 TABLE ACCESS BY INDEX ROWID OBJ#(35873)
1 INDEX UNIQUE SCAN OBJ#(35874) (object id 35874)
1 INDEX RANGE SCAN OBJ#(38516) (object id 38516)
1 TABLE ACCESS BY INDEX ROWID OBJ#(35867)
1 INDEX UNIQUE SCAN OBJ#(35868) (object id 35868)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
SQL*Net message to client 2 0.00 0.00
db file sequential read 1150 0.03 0.59
db file scattered read 2640 0.08 4.72
SQL*Net more data to client 1 0.00 0.00
SQL*Net message from client 2 4.28 4.28
Also we already have an index on clientid, clienttype and another on xref1/objecttype. We gather histograms by default.
Table Name CDN Column NDV Nulls
lgncc_enquiry 1477524
ID 1477524 0
EnquiryType 157 0
Deleteddate 120 1483280
Caseref 118215 1359309
Xref1 76112
lgncc_intloghdr 1595125
Logid 1595125 0
Clientid 80867 1354286
Clienttype 4 0
lgncc_enquiryrelation 1693932
Interactionid 1585278 0
Enquiryid 1477457 0
Relation 3 0
lgncc_enquirytype 197
ID 197 0
Many Thanks
Ronnie
|
|
|