Oracle Left Join需要30多个小时

时间:2017-01-20 21:04:14

标签: sql oracle

关于两个查询的问题:

查询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')

查询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')

查询A: - >执行时间:超过30小时。 - >查询PLan成本:3156361

查询B: - >执行时间:15分钟。 - >查询PLan费用:296107

我认为左连接在两个查询中的工作方式相同,并且它采用相同的数据。如何在时间和成本上产生如此大的差异?

3 个答案:

答案 0 :(得分:2)

您正在将苹果与orages进行比较,因为这两个查询不同
- 它们会产生不同的结果。

由于它们不同,所以它们的计划和执行时间不同也不足为奇。

请检查以下简化示例,以了解它们的不同之处: 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 |

答案 1 :(得分:0)

此时没有任何执行计划,这有点猜测。

我认为问题是LEFT OUTER加入数据范围:

 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')

虽然这在语法上没有任何错误,但它的意思是,不符合日期范围的行被过滤掉,只能由外部联接添加回来。从计划的角度来看,所有过滤都是在post(外部)join之后完成的。

您可以尝试使用以下

 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')

可能有必要看看这些结构中哪一个确实给出了正确的结果

答案 2 :(得分:0)

问题解决了。

这是不正确的并且做了很多嵌套循环:

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')

修复:

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')