简体   繁体   中英

how to generate execution plan for oracle loop

How can I generate execution plan for an oracle loop query like below:

BEGIN 
  FOR L IN (SELECT FIRST_NAME, LAST_NAME, SOME_ID FROM TABLE1)
  LOOP
      INSERT INTO TABLE2 (FIRSTNAME, LASTNAME)
      (SELECT FNAME, LASTNAME FROM TABLE2 WHERE SOME_ID = L.SOME_ID)

  V_CNT := V_CNT + 1;

  IF (MOD(V_CNT, 1000)=0) THEN
    COMMIT;
  END IF;

END LOOP;

How can I generate execution plan for a block like above?

I asked similar question earlier and decided to extract blocks from my stored procedure and generate execution plans for the individually. Though I know how to generate plans for simple queries, I dont know how to generate them for loop blocks like above.

Your PL/SQL block can be re-written in SQL:

INSERT INTO table2 (firstname, lastname)
   SELECT fname, lastname
     FROM table2
    WHERE some_id IN (SELECT some_id FROM table1);

You can then "explain plan" the above INSERT.

If you have to do batch commits then using BULK COLLECT ... LIMIT and FORALL is more efficient than a cursor for loop, especially if you are processing millions of rows. Useful links:

You can't generate execution plans for PL/SQL blocks, only for queries.

Execution plan shows how declarative commands ( SQL ) are executed under the hood, ie what procedures are used. It transforms the declarative constructs (set operations) into procedures (nested loops, hash joins, sorts etc).

PL/SQL , being, as the name suggests, a procedural language, defines the execution plan itself — nested loops in your case.

If you want to see the execution plan for the inner query, you should copy it and issue EXPLAIN PLAN FOR …

Note that this can be more efficiently rewritten as:

BEGIN 
        FOR L IN
        (
        SELECT  MIN(some_id) AS minid, MAX(some_id) AS maxid
        FROM    (
                SELECT  some_id, rownum AS rn
                FROM    (
                        SELECT  some_id
                        FROM    table1
                        ORDER BY
                                some_id
                        )
                )
        GROUP BY
                TRUNC(rn / 1000)
        )
        LOOP
                INSERT
                INTO    TABLE2 (FIRSTNAME, LASTNAME)
                SELECT  FNAME, LASTNAME
                FROM    table1
                JOIN    table2
                ON      table2.some_id = table1.some_id
                WHERE   table1.some_id BETWEEN l.minid AND l.maxid
                V_CNT := V_CNT + 1;
                IF (MOD(V_CNT, 1000)=0) THEN
                        COMMIT;
                END IF;
        END LOOP;
END;

If you are interested in the performance of your procedural PL/SQL code you may want to investigate PL/SQL Profiling.

The Profiler allows you to collect information about the run-time performance of your PL/SQL. After the profiling run is complete you can report on the results and view information like # of times each line was executed, average execution time of each line. This can help you identify bottlenecks and should point you to the first things that may need tuning attention.

Your biggest potential payoff is by looking at the worst performing code and making it run better. Once that is improved, profile again to verify your improvements and to find the next statement that may need attention.

A good first introduction is here: Oracle's DBMS Profiler

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