为什么给定查询挂起或变慢?

时间:2019-06-17 12:22:39

标签: sql oracle oracle11g query-optimization

通常,它执行正常,但有时一周执行一次或两次,在Oracle中挂起或变慢。

是否有更好的方法对其进行优化?

FOR i IN ( SELECT * FROM process_data) LOOP
    BEGIN
        SELECT employee_plan_id
          INTO lc_emp_plan_id
          FROM employee
         WHERE employeeid = i.emp_id
           AND join_year = (
            SELECT join_year
              FROM employeedata
             WHERE employeeid = i.emp_id
               AND i.joining_date BETWEEN join_date AND termination_date
        );
    END;
    SELECT employee_plan_type
      INTO lc_emp_type
      FROM employee_plans
     WHERE employee_plan_id = lc_emp_plan_id;

    -- Mark failed record if emp_lastname is null
    UPDATE process_data
       SET
        is_failure = 1
     WHERE emp_lastname IS NULL
       AND emp_plan_type = lc_emp_type;
END LOOP;

记住

SELECT join_year
  FROM employeedata
 WHERE employeeid = i.emp_id
   AND i.joining_date BETWEEN joining_date AND termination_date;

它将始终返回1条记录,并且已被证明。

lc_emp_plan_id是一个变量,并且此for循环在过程内执行吗?

1 个答案:

答案 0 :(得分:2)

对观察到的行为的最原始的解释是,要处理的行数(process_data)有所不同。 总经过时间与已处理的行数成线性比例,因此在行数较多的日子,循环“挂起”。

提高速度的最佳方法是不要在PL / SQL中使用FOR LOOP

在SQL语句中对其进行简单的重新构造(这并非总是可能的,有时会导致复杂的SQL,但可能会大大提高速度。

在您的情况下,这应该是相当简单的练习:

此查询返回的结果与您的第一个循环相同。

SELECT e.employee_plan_id
  FROM process_data p
  JOIN employee e ON p.emp_id = e.employeeid
  JOIN employeedata ed ON p.emp_id = ed.employeeid
   AND p.joining_date BETWEEN ed.join_date AND ed.termination_date;

因此,您可以使用一个UPDATE语句重写整个过程。

UPDATE process_data
   SET is_failure = 1
 WHERE emp_lastname IS NULL
   AND emp_plan_type IN (
    SELECT employee_plan_type
      FROM employee_plans
     WHERE employee_plan_id IN (
        /* copy the query above here */
    )
);