简体   繁体   中英

Why given query hangs or slow down?

Usually, it executes ok but sometimes once or twice in a week, it got hanged or slowdown in Oracle.

Is there a better way to optimize it?

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;

Remember

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

It will always return 1 record and that is proven.

Here lc_emp_plan_id is a variable and this for loop executes within procedure?

The most native explanation of the observed behaviour is, that the number of rows to be processed ( process_data ) varies. The total elapsed time is linearly proportional to the number of processed rows, so on the days with lot of rows the loop "hangs".

A best way to speed up a is not to use FOR LOOP in PL/SQL.

Simple reformultion it in a SQL statement (this is not always possible, sometimes leads to a complex SQL, but may produce a dramatic speed up.

In your case this should be rather simple exercise:

This query returns the same result as your first loop.

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;

Accordingly, you can rewrite the whole procedure with one UPDATE statement.

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 */
    )
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM