Reputation: 1318
A question about two Queries:
Query A:
SELECT ******
FROM WORK_ORDERS w
LEFT JOIN (
SELECT crew.WO_ID, EMP.DOCUMENT_NUMBER|| '-'|| emp.FIRST_NAME|| ' '|| emp.LAST_NAME helpers
FROM WORK_ORDER_CREW_ASSIGMENTS crew
INNER JOIN EMPLOYEE_CREWS employeeCrew
ON employeeCrew.CREW_ID = crew.CREW_ID AND employeeCrew.IS_RESPONSIBLE = 'N'
INNER JOIN EMPLOYEES emp ON EMP.id = EMPLOYEECREW.EMPLOYEE_ID
WHERE crew.IS_ACTIVE = 'S'
) crewHelpers
ON (w.id = crewHelpers.wo_id)
and w.CREATION_DATE between
to_date('01/01/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
and to_date('01/04/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
Query B:
SELECT ******
FROM WORK_ORDERS w
LEFT JOIN WORK_ORDER_CREW_ASSIGMENTS crew
ON CREW.WO_ID = w.ID
INNER JOIN EMPLOYEE_CREWS employeeCrew
ON employeeCrew.CREW_ID = crew.CREW_ID
AND employeeCrew.IS_RESPONSIBLE = 'N'
INNER JOIN EMPLOYEES emp
ON EMP.id = EMPLOYEECREW.EMPLOYEE_ID
WHERE crew.IS_ACTIVE = 'S'
and w.CREATION_DATE between
to_date('01/01/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
and to_date('01/04/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
Query A: -> Time of Execution: More than 30 Hours. -> Query PLan Cost: 3156361
Query B: -> Time of Execution: 15 Minutes. -> Query PLan Cost: 296107
I think the left join works the same in both queries, and it takes the same data. How can there be so much difference in time and cost from one to another?
Upvotes: 0
Views: 97
Reputation: 1318
Problem solved.
This was incorrect and done a lot of nested loops:
LEFT JOIN (SELECT crew.WO_ID, EMP.DOCUMENT_NUMBER|| '-'|| emp.FIRST_NAME|| ' '|| emp.LAST_NAME helpers
FROM WORK_ORDER_CREW_ASSIGMENTS crew
INNER JOIN EMPLOYEE_CREWS employeeCrew ON employeeCrew.CREW_ID = crew.CREW_ID AND employeeCrew.IS_RESPONSIBLE = 'N'
INNER JOIN EMPLOYEES emp ON EMP.id = EMPLOYEECREW.EMPLOYEE_ID WHERE crew.IS_ACTIVE = 'S'
) crewHelpers ON (w.id = crewHelpers.wo_id)
->**AND**<- w.CREATION_DATE between to_date('01/01/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss') and to_date('01/04/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
The fix:
LEFT JOIN (SELECT crew.WO_ID, EMP.DOCUMENT_NUMBER|| '-'|| emp.FIRST_NAME|| ' '|| emp.LAST_NAME helpers
FROM WORK_ORDER_CREW_ASSIGMENTS crew
INNER JOIN EMPLOYEE_CREWS employeeCrew ON employeeCrew.CREW_ID = crew.CREW_ID AND employeeCrew.IS_RESPONSIBLE = 'N'
INNER JOIN EMPLOYEES emp ON EMP.id = EMPLOYEECREW.EMPLOYEE_ID WHERE crew.IS_ACTIVE = 'S'
) crewHelpers ON (w.id = crewHelpers.wo_id)
->**WHERE**<- w.CREATION_DATE between to_date('01/01/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss') and to_date('01/04/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
Upvotes: 0
Reputation: 4434
Without any execution plans to go on at this time, this is somewhat of a guess.
I think the issue is the the LEFT OUTER join on a the data range:
ON (w.id = crewHelpers.wo_id)
AND w.CREATION_DATE BETWEEN to_date('01/01/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
AND to_date('01/04/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
While there is nothing syntactically wrong with this, what it does mean is that the rows that do not meet the date range ar filtered out only to be added back by the outer join. From a plan perspective, all the filtering is done post (outer) join.
Can you try with the following
ON (w.id = crewHelpers.wo_id)
WHERE w.CREATION_DATE BETWEEN to_date('01/01/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
AND to_date('01/04/2016 00:00:00','DD/MM/YYYY HH24:Mi:ss')
It may be necessary to see which of these constructs does indeed give the correct results
Upvotes: 0
Reputation: 36107
You are comparing apples to orages, because these two queries are different
- they give different results.
Since they are different, so it is not a big surprise that their plans and execution times differ.
Please examine the below simplified example to understand why they are different:
http://sqlfiddle.com/#!9/93e681/4
CREATE TABLE WORK_ORDERS(
id int
);
INSERT INTO WORK_ORDERS VALUES (1),(2),(3);
CREATE TABLE WORK_ORDER_CREW(
wo_id int,
IS_ACTIVE char(1)
);
INSERT INTO WORK_ORDER_CREW VALUES(1,'Y'),(3,'S');
SELECT *
FROM WORK_ORDERS w
LEFT JOIN WORK_ORDER_CREW crew
ON w.id = crew.wo_id
WHERE crew.IS_ACTIVE = 'S'
;
| id | wo_id | IS_ACTIVE |
|----|-------|-----------|
| 3 | 3 | S |
SELECT *
FROM WORK_ORDERS w
LEFT JOIN (
SELECT * FROM WORK_ORDER_CREW crew
WHERE crew.IS_ACTIVE = 'S'
) crew
ON w.id = crew.wo_id;
| id | wo_id | IS_ACTIVE |
|----|--------|-----------|
| 1 | (null) | (null) |
| 2 | (null) | (null) |
| 3 | 3 | S |
Upvotes: 2