Introduction
I had a complex SQL query that was used to extract data from my system and send it across via web request to an external system. The query was taking unduly longer time to run. I made few changes to the query structure and reduced it run time to 7 mins. A part of the main query that was actually causing the delay has been pasted in the sections below.
Problem Description
One of my external systems reported that one of the queries that run at my end have failed with the error below:
ORA-20001: Error - WebService Request Failed. ORA-29276: transfer timeout.
When I tried running the SELECT query in question at my end (on Toad), the query kept running after I aborted it after almost 90 minutes.
The central part of the original query is as below. This part was causing the entire query to slow down. The tables TEAM, TIMESHEET, TIMEENTRY and ASSIGNMENT are considerably huge tables with billions of records. The explain plan showed a full table access on ASSIGNMENT and TIMESHEET tables.
The code
Problem
Code: SQL
SELECT TP.START STARTED ,
TP.FINISH FINISHED,
TP.ID PERIOD,
TM.PROJECTID PROJECTID,
TM.ID TEAMID,
TM.RESOURCEID RESOURCEID,
SUM(TE.ACT) ACT
FROMTASK TK,
TEAM TM,
ASSIGNMENT ASM,
TIMEENTRY TE,
PERIOD TP,
(SELECTMAX(A.ID)ID,PERIODID,RESOURCEID
FROM TIMESHEET A, PERIOD B
WHERE STATUS IN(1,3,4)AND ADJUSTMENT =0
ANDA.periodid = B.id
ANDTRUNC(B.START)>=TRUNC(NEXT_DAY(NVL(NULL,SYSDATE)-28,'MONDAY'))
GROUPBY PERIODID,RESOURCEID)TS
WHERE TM.PROJECTID IN(SELECT PRJ.ID
FROM PROJECTS PRJ,
CU_PROJECT CU,
PRJ_ASSOC AS,
PRJ_UNITS OBS,
PRJ_TYPES TYPE
WHEREAS.TABLE_NAME ='PROJECTS'
ANDAS.RECORD_ID = PRJ.ID
ANDAS.UNIT_ID = OBS.ID
AND OBS.TYPE_ID=TYPE.ID
ANDTYPE.NAME='TEST1'
AND CU.ID=PRJ.ID
AND CU.PRT_CODE='TEST2')
AND TK.PROJECTID=TM.PROJECTID
AND ASM.TASKID=TK.ID
AND ASM.RESOURCEID=TM.RESOURCEID
AND TE.TIMESHEETID=TS.ID
AND TS.PERIODID=TP.ID
AND TE.ASSIGNID=ASM.ID
ANDTRUNC(TP.START)>=TRUNC(NEXT_DAY(NVL(NULL,SYSDATE)-28,'MONDAY'))
GROUPBY TP.START,TM.ID,TM.RESOURCEID,TM.PROJECTID,TP.ID,TP.FINISH
I changed the query structure as below. This query took 7 mins to run, a considerable improvement from the old query:
Code:
WITH TS AS(SELECT/*+ materialize */MAX(A.ID)ID,PERIODID,RESOURCEID FROM TIMESHEET A, PERIOD B WHERE STATUS IN(1,3,4)AND ADJUSTMENT =0 ANDA.periodid = B.id ANDTRUNC(B.START)>=TRUNC(NEXT_DAY(NVL(NULL,SYSDATE)-28,'MONDAY')) GROUPBY PERIODID,RESOURCEID) SELECT TP.START STARTED , TP.FINISH FINISHED, TP.ID PERIOD, TM.PROJECTID PROJECTID, TM.ID TEAMID, TM.RESOURCEID RESOURCEID, SUM(TE.ACT) ACT FROMTASK TK, TEAM TM, ASSIGNMENT ASM, TIMEENTRY TE, PERIOD TP, (SELECT PRJ.ID FROM PROJECTS PRJ, CU_PROJECT CU, PRJ_ASSOC AS, PRJ_UNITS OBS, PRJ_TYPES TYPE WHEREAS.TABLE_NAME ='PROJECTS' ANDAS.RECORD_ID = PRJ.ID ANDAS.UNIT_ID = OBS.ID AND OBS.TYPE_ID=TYPE.ID ANDTYPE.NAME='TEST1' AND CU.ID=PRJ.ID AND CU.PRT_CODE='TEST2')S, WHERE TK.PROJECTID=TM.PROJECTID AND ASM.TASKID=TK.ID AND ASM.RESOURCEID=TM.RESOURCEID AND S.ID= TM.PROJECTID AND TE.TIMESHEETID=TS.ID AND TS.RESOURCEID = TM.RESOURCEID AND TS.PERIODID=TP.ID AND TE.ASSIGNID=ASM.ID AND TP.START>=TRUNC(NEXT_DAY(NVL(NULL,SYSDATE)-28,'MONDAY')) GROUPBY TP.START,TM.ID,TM.RESOURCEID,TM.PROJECTID,TP.ID,TP.FINISH
More readable code by Nimesh
Code: sql
SELECT TP.START STARTED
, TP.FINISH FINISHED
, TP.ID PERIOD
, TM.PROJECTID PROJECTID
, TM.ID TEAMID
, TM.RESOURCEID RESOURCEID
, SUM(TE.ACT) ACT
FROM TASK TK
, TEAM TM
, ASSIGNMENT ASM
, TIMEENTRY TE
, PERIOD TP
, (SELECT MAX(A.ID) ID
, PERIODID
, RESOURCEID
FROM TIMESHEET A
, PERIOD B
WHERE STATUS IN (1,3,4)
AND ADJUSTMENT = 0
AND A.periodid = B.id
AND TRUNC(B.START) >= TRUNC(NEXT_DAY(NVL(NULL,SYSDATE)-28,'MONDAY'))
GROUP BY PERIODID
, RESOURCEID
) TS
WHERE TM.PROJECTID IN (SELECT PRJ.ID
FROM PROJECTS PRJ
, CU_PROJECT CU
, PRJ_ASSOC AS
, PRJ_UNITS OBS
, PRJ_TYPES TYPE
WHERE AS.TABLE_NAME = 'PROJECTS'
AND AS.RECORD_ID = PRJ.ID
AND AS.UNIT_ID = OBS.ID
AND OBS.TYPE_ID=TYPE.ID
AND TYPE.NAME='TEST1'
AND CU.ID=PRJ.ID
AND CU.PRT_CODE='TEST2'
)
AND TK.PROJECTID = TM.PROJECTID
AND ASM.TASKID = TK.ID
AND ASM.RESOURCEID = TM.RESOURCEID
AND TE.TIMESHEETID = TS.ID
AND TS.PERIODID = TP.ID
AND TE.ASSIGNID = ASM.ID
AND TRUNC(TP.START) >= TRUNC(NEXT_DAY(NVL(NULL,SYSDATE)-28,'MONDAY'))
GROUP BY TP.START
, TM.ID
, TM.RESOURCEID
, TM.PROJECTID
, TP.ID
, TP.FINISH
nimesh
like this





