谁能告诉我为什么这个sp需要这么多时间?

时间:2014-03-17 06:27:27

标签: plsql plsqldeveloper

执行以下存储过程时需要20分钟。预计时间为2-3分钟。 为什么会这样? 谁能告诉我为什么这个sp花了这么多时间?可以做些什么来让它跑得更快? 非常感谢提前。这个程序的逻辑是,它检查表中是否存在订单号,如果没有则插入该表

 CREATE OR REPLACE PROCEDURE sp_load_order
    IS
       l_ds_ds_id               data_source.ds_id%TYPE;
       l_carrier                stage_na_shipment.haulier_name%TYPE;
       l_vehicle_number         stage_na_shipment.haulier_num%TYPE;
       l_ship_date              stage_na_shipment.ship_date`enter code here`%TYPE;
       l_source_key             VARCHAR2 (20);
       l_source_key_1           VARCHAR2 (20);
       l_quantity               stage_na_shipment.quantity%TYPE;
       l_ship_from              stage_na_shipment.ship_from%TYPE;
       l_prod_prod_id           product.prod_prod_id%TYPE;
       l_client                 stage_na_shipment.client%TYPE;
       l_ord_id                 ordr.ord_id%TYPE;
       l_sf_sf_id               ship_from.sf_id%TYPE;
       l_cust_cust_id           customer.cust_cust_id%TYPE;
       l_ord_stat_ord_stat_id   ordr_status.ord_stat_id%TYPE;
       l_le_le_id               legal_entity.le_id%TYPE;
       l_mkt_mkt_id             market.mkt_id%TYPE;
       l_code                   bill_type.code%TYPE;
       l_ord_ord_id             ordr.ord_id%TYPE;
       l_ord_prod_id            ordr_product.ord_prod_id%TYPE;
       l_po_number              stage_na_shipment.po_number%TYPE;
       l_expct_ship_date        stage_na_shipment.ship_date%TYPE;
       l_bt_bt_id               bill_type.bt_id%TYPE;
       l_order_process_date     stage_na_shipment.ship_date%TYPE;
       l_storage_loc            stage_na_shipment.stor_loc%TYPE;
       l_ship_unit_code_8       stage_na_shipment.ship_unit_code_8%TYPE;
       l_del_point              stage_na_shipment.DEL_POINT%type;
       l_r_num                  NUMBER;
       n_1                      NUMBER;
       l_error_msg              VARCHAR2 (500);
       start_time timestamp;
       end_time timestamp;
    BEGIN
    start_time:=systimestamp;
         DBMS_OUTPUT.put_line ('Procedure started' ||start_time);

       sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', 'START', NULL, NULL, NULL);

       start_time:=systimestamp;
         DBMS_OUTPUT.put_line ('DS_ID start_time' ||start_time);

       SELECT ds_id
        INTO l_ds_ds_id
         FROM data_source
        WHERE ds_id = 1;

       DBMS_OUTPUT.put_line ('DS_ID' || l_ds_ds_id);

        end_time:=systimestamp;
         DBMS_OUTPUT.put_line ('DS_ID start_time' ||end_time);

       start_time:=systimestamp;
         DBMS_OUTPUT.put_line ('ord_stat_id start_time' ||start_time);

       SELECT ord_stat_id
         INTO l_ord_stat_ord_stat_id
         FROM ordr_status
        WHERE ord_stat_id = 2;

     DBMS_OUTPUT.put_line ('ORD_STAT_ID' || l_ord_stat_ord_stat_id);

       end_time:=systimestamp;
         DBMS_OUTPUT.put_line ('ORD_STAT_ID end_time' ||end_time);


     start_time:=systimestamp;
         DBMS_OUTPUT.put_line ('le_id start_time' ||start_time);

       SELECT le_id
         INTO l_le_le_id
         FROM legal_entity
        WHERE le_id = 1;

       DBMS_OUTPUT.put_line ('LE_ID' || l_le_le_id);
       end_time:=systimestamp;
         DBMS_OUTPUT.put_line ('LE_ID end_time' ||end_time);

          SELECT COUNT (*)
            INTO l_r_num
            FROM frontroom.ordr;

          sp_log_entry (SYSDATE,
                        'SP_LOAD_ORDER',
                        'MESSAGE',
                        'FRONTROOM_BEF_INS',
                        l_r_num,
                        NULL
                       );

          SELECT COUNT (*)
            INTO l_r_num
            FROM frontroom.ordr_product;

          sp_log_entry (SYSDATE,
                        'SP_LOAD_ORDER',
                        'MESSAGE',
                        'ORDRPRODUCT_BEFORE_INS',
                        l_r_num,
                        NULL
                       );


        DBMS_OUTPUT.put_line ('loop started' ||start_time);

       FOR i IN (SELECT order_num_cos, ship_date, haulier_name, haulier_num,
                        po_number, stor_loc, ship_unit_code, ship_unit_code_8,
                        so_item, ship_from, del_point, currency, client, quantity
                   FROM stage_na_shipment)
       LOOP

          l_source_key := TO_CHAR (i.order_num_cos);
          l_carrier := TO_CHAR (i.haulier_name);
          l_vehicle_number := TO_CHAR (i.haulier_num);
          l_source_key_1 := TO_CHAR (i.order_num_cos || i.so_item);
          l_po_number := i.po_number;
          l_storage_loc := TO_CHAR (i.stor_loc);
          l_del_point :=i.del_point;
          l_ship_date := i.ship_date;
          l_ship_from := TO_CHAR (i.ship_from);
          l_ship_unit_code_8 := TO_CHAR (i.ship_unit_code_8);
          l_client := TO_CHAR (i.client);


          DBMS_OUTPUT.put_line ('order_number' || i.order_num_cos);

          BEGIN
          start_time:=systimestamp;
           DBMS_OUTPUT.put_line ('mkt_id start_time' ||start_time);

             SELECT mkt_id  INTO l_mkt_mkt_id
               FROM market
              WHERE code =  DECODE (SUBSTR (l_client, 1, 4), 'US23', 'MM',
                                            'US99', 'AFFCO' );

             DBMS_OUTPUT.put_line ('MKT_ID' || l_mkt_mkt_id);
          EXCEPTION
             WHEN NO_DATA_FOUND
             THEN
                sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL,  'THE MKT ID  NOT FOUND  :',
                              NULL, NULL  );
                GOTO end_loop;

                WHEN TOO_MANY_ROWS THEN
                 sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL,  'MKT ID TWO MANY ROWS  FOUND  :'||i.order_num_cos,
                              NULL, NULL  );

             WHEN others
             THEN
                sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, SQLERRM, NULL, NULL );
          END;
     end_time:=systimestamp;
         DBMS_OUTPUT.put_line ('mkt_id end_time' ||end_time);

     start_time:=systimestamp;
           DBMS_OUTPUT.put_line ('bt_id start_time' ||start_time);


          BEGIN
             IF i.quantity >= 0
             THEN
                l_code := 'O';
             ELSE
                l_code := 'C';
             END IF;

             SELECT bt_id  INTO l_bt_bt_id  FROM bill_type
                        WHERE code = l_code
                         AND ds_ds_id = l_ds_ds_id;

          EXCEPTION
             WHEN NO_DATA_FOUND
             THEN
                sp_log_entry
                           (SYSDATE,
                            'SP_LOAD_ORDER',
                            NULL,
                            'BILL TYPE ID NOT FOUND',
                            NULL,
                            NULL
                           );
                           GOTO end_loop;


                         WHEN TOO_MANY_ROWS THEN
                 sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL,  'BILL TYPE ID TWO MANY ROWS  FOUND  :'||i.order_num_cos,
                              NULL, NULL  );

                           WHEN others
             THEN
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              SQLERRM,
                              NULL,
                              NULL
                             );
          END;

          DBMS_OUTPUT.put_line ('BT_ID   :' || l_bt_bt_id);

           end_time:=systimestamp;
         DBMS_OUTPUT.put_line ('BT_ID end_time' ||end_time);

       start_time:=systimestamp;
           DBMS_OUTPUT.put_line ('prod_id start_time' ||start_time);

          BEGIN
             SELECT prod_prod_id
               INTO l_prod_prod_id
               FROM product
              WHERE secondary_source_key = LTRIM (l_ship_unit_code_8, 0);
          EXCEPTION
             WHEN NO_DATA_FOUND
             THEN
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              'THE PRODUCT ID '  ||i.ship_unit_code_8 ||' could not be found in product table :',
                'order_num_cos = ' || i.order_num_cos
                              ,
                              NULL
                             );
                             GOTO end_loop;

                             WHEN TOO_MANY_ROWS THEN
                 sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL,  'THE PRODUCT ID TWO MANY ROWS  FOUND  :' ||i.order_num_cos,
                              NULL, NULL  );

             WHEN OTHERS
             THEN
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              SQLERRM,
                              i.ship_unit_code_8 || SQLERRM,
                              NULL
                             );
          END;

         DBMS_OUTPUT.put_line (' PROD_PROD_ID  :' || l_prod_prod_id);

         end_time:=systimestamp;
         DBMS_OUTPUT.put_line ('PROD_ID end_time' ||end_time);

          start_time:=systimestamp;
           DBMS_OUTPUT.put_line ('sf_id start_time' ||start_time);

          BEGIN
             SELECT sf_id
               INTO l_sf_sf_id
               FROM ship_from
              WHERE source_key = l_ship_from;
          EXCEPTION
             WHEN NO_DATA_FOUND
             THEN
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              'sf_id NOT FOUND',
                              NULL,
                              NULL
                             );
                             GOTO end_loop;

                             WHEN TOO_MANY_ROWS THEN
                 sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL,  'sf_id TWO MANY ROWS  FOUND  :'||i.order_num_cos,
                              NULL, NULL  );

                             WHEN others
             THEN
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              SQLERRM,
                              NULL,
                              NULL
                             );

          END;

         DBMS_OUTPUT.put_line ('SF_ID  :' || l_sf_sf_id);

         end_time:=systimestamp;
           DBMS_OUTPUT.put_line ('sf_id end_time' ||end_time);

    start_time:=systimestamp;
           DBMS_OUTPUT.put_line ('cust_id start_time' ||start_time);


          BEGIN
             SELECT cust_id
               INTO l_cust_cust_id
               FROM customer
              WHERE true_gcdb_source_key = to_char(i.del_point);
              -- AND ds_ds_id = l_ds_ds_id;
          EXCEPTION
             WHEN NO_DATA_FOUND
             THEN
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              'THE CUST ID ' || l_del_point || 'COULD NOT BE FOUND IN THE CUSTOMER TABLE''order_num_cos = '||i.order_num_cos,
                              NULL,
                              NULL
                             );
                             GOTO end_loop;


                             WHEN TOO_MANY_ROWS THEN
                 sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL,  'cust_id TWO MANY ROWS  FOUND  :'||i.order_num_cos,
                              NULL, NULL  );

            WHEN others
             THEN
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              SQLERRM,
                              NULL,
                              NULL
                             );
          END;

         DBMS_OUTPUT.put_line ('CUST_ID  :' || l_cust_cust_id);

         end_time:=systimestamp;
           DBMS_OUTPUT.put_line ('CUST_ID end_time' ||end_time);

    start_time:=systimestamp;
       DBMS_OUTPUT.put_line ('INSERTING INTO frontroom.ordr' ||start_time);

          BEGIN
             INSERT INTO frontroom.ordr
                         (ord_number, ds_ds_id, erlst_ship_dt, carrier,
                          vehicle_number, ord_dt, source_key, sf_sf_id,
                          cust_cust_id, ord_stat_ord_stat_id, le_le_id,
                          mkt_mkt_id, sc_sc_id, ctrl_dt, po_number,
                          expct_ship_date, bt_bt_id, order_process_dt,
                          storage_loc)
                SELECT l_source_key, l_ds_ds_id, i.ship_date, l_carrier,
                       l_vehicle_number, i.ship_date, l_source_key, l_sf_sf_id,
                       l_cust_cust_id, l_ord_stat_ord_stat_id, l_le_le_id,
                       l_mkt_mkt_id, 0, i.ship_date, l_po_number, i.ship_date,
                       l_bt_bt_id, i.ship_date, l_storage_loc
                  FROM DUAL
                 WHERE NOT EXISTS (SELECT 1--ord_number
                                     FROM frontroom.ordr
                                    WHERE ord_number = l_source_key);

          EXCEPTION
             WHEN OTHERS
             THEN
                l_error_msg := SQLERRM;
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              l_error_msg,
                             'order_num_cos = ' || i.order_num_cos,
                              NULL
                             );
                             GOTO end_loop;
          END;

         DBMS_OUTPUT.put_line ('Inserted into order table');

          end_time:=systimestamp;
           DBMS_OUTPUT.put_line ('Inserted into order table' ||end_time);



          SELECT ord_id
            INTO l_ord_ord_id
            FROM frontroom.ordr
           WHERE ord_number = l_source_key;


    start_time:=systimestamp;
       DBMS_OUTPUT.put_line ('INSERTING INTO frontroom.ordr_product' ||start_time);

          BEGIN
             INSERT INTO ordr_product
                         (volume, revenue, source_key, ord_ord_id, prod_prod_id,
                          local_currency)
                SELECT i.ship_unit_code, 0, l_source_key_1, l_ord_ord_id,
                       l_prod_prod_id, i.currency
                  FROM DUAL
                 WHERE NOT EXISTS (
                             SELECT 1--ord_ord_id
                               FROM ordr_product
                              WHERE ord_ord_id =
                                               (SELECT ord_id
                                                  FROM ordr
                                                 WHERE ord_number = l_source_key));

          EXCEPTION
             WHEN OTHERS
             THEN
                l_error_msg := SQLERRM;
                sp_log_entry (SYSDATE,
                              'SP_LOAD_ORDER',
                              NULL,
                              l_error_msg,
                             'order_num_cos = ' || i.order_num_cos,
                              NULL
                             );
                             GOTO end_loop;
          END;

          n_1 := n_1 + 1;
          if n_1 = 100 then
                   COMMIT;
                    n_1 :=  0;
          end if;

          <<end_loop>>
          null;


       END LOOP;
         end_time:=systimestamp;
           DBMS_OUTPUT.put_line ('Inserted into order table' ||end_time);


        end_time:=systimestamp;

    DBMS_OUTPUT.put_line ('Loop ends' ||end_time);

          SELECT COUNT (*)
            INTO l_r_num
            FROM frontroom.ordr;

          sp_log_entry (SYSDATE,
                        'SP_LOAD_ORDER',
                        'MESSAGE',
                        'FRONTROOM_AFTER_INS',
                        l_r_num,
                        NULL
                       );

       SELECT COUNT (*)
         INTO l_r_num
         FROM frontroom.ordr_product;

       sp_log_entry (SYSDATE,
                     'SP_LOAD_ORDER',
                     'MESSAGE',
                     'ORDRPRODUCT_AFTER_INS',
                     l_r_num,
                     NULL
                    );
       sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', 'COMPLETE', NULL, NULL, NULL);

         end_time:=systimestamp;
         DBMS_OUTPUT.put_line ('Procedure ends' ||end_time);

       COMMIT;

    EXCEPTION
       WHEN OTHERS
       THEN
          l_error_msg := SQLERRM;
          sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, l_error_msg, NULL, NULL);
    END sp_load_order;
    /

2 个答案:

答案 0 :(得分:2)

幸运的是,你正在使用PL / SQL Developer,这使得PL / SQL分析非常容易。

  1. 打开测试窗口,文件 - &gt;新建 - &gt;测试窗口。
  2. sp_load_order;添加到中间。
  3. 单击顶部的仪表图标以启用分析。
  4. 按F8或运行按钮运行程序。等待它完成。
  5. 单击“Profiler”选项卡。
  6. 点击列&#34;总时间&#34;排序降序。
  7. 然后你会确切知道程序的哪些行很慢。

答案 1 :(得分:1)

在不知道数据库的情况下,很难弄清问题是什么,尤其是像这样的大型程序。

但是你可以考虑一些事情:

您正在循环中执行DML(插入),通常使用批量操作可以获得相当大的性能提升。欲了解更多信息,请查看:http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/tuning.htm#i48876 可在此处找到更“用户友好”的说明:http://www.oracle-base.com/articles/9i/bulk-binds-and-record-processing-9i.php 请注意,如果您不熟悉批量操作,首先要破解它可能是一个难题。

在做任何激烈的事情之前(问题可能像缺失的索引一样简单)你可以先跟踪它来分析问题。

要做到这一点,首先必须启动te程序,并使用此查询(来自另一个会话)找出它的会话ID和序列号:

select username, status, sid, serial# from v$session

完成后,您可以使用以下命令启动跟踪:

exec dbms_monitor.session_trace_enable(session_id=>3,serial_num=>5027,binds=>true,waits=>true);

程序完成后,您可以停止跟踪:

exec dbms_monitor.session_trace_disable(session_id=>3,serial_num=>5027);

Oracle现在已经编写了一些跟踪文件,以确定oracle放置它们的位置,执行此命令:

SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Default Trace File'; 

跟踪文件的可读性不是很高,但您可以使用tkprof命令行实用程序获取可读报告。您可以从命令行运行if:

tkprof <source trace file> <output file>

现在,您将拥有一个包含已在其中运行的所有查询的文件,并且每个报告一个这样的表格:

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        9      0.00       0.00          0          0          0           0
Execute      9      0.00       0.01          1         32          0           1
Fetch        3      0.00       0.00          0         32          0           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       21      0.00       0.01          1         64          0           2

通过这种方式,您可以找出查询时间最长的查询。 你也可以从中获得这样的信息,它可以告诉你已运行的查询数量:

1  session in tracefile.
9  user  SQL statements in trace file.
2  internal SQL statements in trace file.
11  SQL statements in trace file.
10  unique SQL statements in trace file.
504  lines in trace file.
4  elapsed seconds in trace file.

P.S。所有追查样本均由http://tinky2jed.wordpress.com/technical-stuff/oracle-stuff/what-is-the-correct-way-to-trace-a-session-in-oracle/

提供