《Oracle PL/SQL实例精讲》学习笔记26——优化PL/SQL(第二部分——PL/SQL优化级别)

本章内容:

1. PL/SQL调优工具

2. PL/SQL优化级别

3. 子程序内联

 

代码如下:

1. 查看PROFTAB.sql内容

Rem
Rem $Header: plsql/admin/proftab.sql /main/4 2013/07/08 10:56:15 sylin Exp $
Rem
Rem proftab.sql
Rem
Rem Copyright (c) 1998, 2013, Oracle and/or its affiliates. 
Rem All rights reserved.
Rem
Rem    NAME
Rem      proftab.sql
Rem
Rem    DESCRIPTION
Rem      Create tables for the PL/SQL profiler
Rem
Rem    NOTES
Rem      The following tables are required to collect data:
Rem        plsql_profiler_runs  - information on profiler runs
Rem        plsql_profiler_units - information on each lu profiled
Rem        plsql_profiler_data  - profiler data for each lu profiled
Rem
Rem      The plsql_profiler_runnumber sequence is used for generating unique
Rem      run numbers.
Rem
Rem      The tables and sequence can be created in the schema for each user
Rem      who wants to gather profiler data. Alternately these tables can be
Rem      created in a central schema. In the latter case the user creating
Rem      these objects is responsible for granting appropriate privileges
Rem      (insert,update on the tables and select on the sequence) to all 
Rem      users who want to store data in the tables. Appropriate synonyms 
Rem      must also be created so the tables are visible from other user 
Rem      schemas.
Rem
Rem      The other tables are used for rolling up to line level; the views are
Rem      used to roll up across multiple runs. These are not required to 
Rem      collect data, but help with analysis of the gathered data. 
Rem
Rem      THIS SCRIPT DELETES ALL EXISTING DATA!
Rem
Rem    MODIFIED   (MM/DD/YY)
Rem    sylin       06/12/13 - long identifier
Rem    jmuller     10/07/99 - Fix bug 708690: TAB -> blank
Rem    astocks     04/19/99 - Add owner,related_run field to runtab
Rem    astocks     10/21/98 - Add another spare field
Rem    ciyer       09/15/98 - Create tables for profiler
Rem    ciyer       09/15/98 - Created
Rem

drop table plsql_profiler_data cascade constraints;
drop table plsql_profiler_units cascade constraints;
drop table plsql_profiler_runs cascade constraints;

drop sequence plsql_profiler_runnumber;

create table plsql_profiler_runs
(
  runid           number primary key,  -- unique run identifier,
                                       -- from plsql_profiler_runnumber
  related_run     number,              -- runid of related run (for client/
                                       --     server correlation)
  run_owner       varchar2(32),        -- user who started run -- dbms_id
  run_date        date,                -- start time of run
  run_comment     varchar2(2047),      -- user provided comment for this run
  run_total_time  number,              -- elapsed time for this run
  run_system_info varchar2(2047),      -- currently unused
  run_comment1    varchar2(2047),      -- additional comment
  spare1          varchar2(256)        -- unused
);

comment on table plsql_profiler_runs is
        'Run-specific information for the PL/SQL profiler';

create table plsql_profiler_units
(
  runid              number references plsql_profiler_runs,
  unit_number        number,           -- internally generated library unit #
  unit_type          varchar2(32),     -- library unit type
  unit_owner         varchar2(32),     -- library unit owner name -- dbms_id
  unit_name          varchar2(32),     -- library unit name -- dbms_id
  -- timestamp on library unit, can be used to detect changes to
  -- unit between runs
  unit_timestamp     date,
  total_time         number DEFAULT 0 NOT NULL,
  spare1             number,           -- unused
  spare2             number,           -- unused
  --  
  primary key (runid, unit_number)
);

comment on table plsql_profiler_units is 
        'Information about each library unit in a run';

create table plsql_profiler_data
(
  runid           number,           -- unique (generated) run identifier
  unit_number     number,           -- internally generated library unit #
  line#           number not null,  -- line number in unit
  total_occur     number,           -- number of times line was executed
  total_time      number,           -- total time spent executing line
  min_time        number,           -- minimum execution time for this line
  max_time        number,           -- maximum execution time for this line
  spare1          number,           -- unused
  spare2          number,           -- unused
  spare3          number,           -- unused
  spare4          number,           -- unused
  --
  primary key (runid, unit_number, line#),
  foreign key (runid, unit_number) references plsql_profiler_units
);

comment on table plsql_profiler_data is 
        'Accumulated data from all profiler runs';

create sequence plsql_profiler_runnumber start with 1 nocache;

2. 在C##STUDENT模式下运行PROFTAB.sql脚本

SQL> show user
USER is "C##STUDENT"
SQL> @D:\app\pdh\product\12.1.0\dbhome_2\RDBMS\ADMIN\proftab.sql

Table dropped.


Table dropped.


Table dropped.


Sequence dropped.


Table created.


Comment created.


Table created.


Comment created.


Table created.


Comment created.


Sequence created.

3. 在SYS模式下运行PROFLOAD.sql脚本,并对C##STUDENT授权

SQL> @D:\app\pdh\product\12.1.0\dbhome_2\RDBMS\ADMIN\profload.sql

Session altered.


Package created.


Grant succeeded.


Synonym created.


Session altered.


Session altered.


Library created.


Package body created.


Session altered.

Testing for correct installation
SYS.DBMS_PROFILER successfully loaded.

PL/SQL procedure successfully completed.

SQL> grant execute on dbms_profiler to c##student
  2  ;

Grant succeeded.

4. 在c##student模式下测试1 (Optimizer level at 0)

SQL> show user
USER is "C##STUDENT"
SQL> SET TIMING ON;
SQL> ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 0;

Session altered.

Elapsed: 00:00:00.00
SQL> /* Formatted on 2018/11/20 0:01:52 (QP5 v5.256.13226.35538) */
SQL> DECLARE
  2     v_num1     NUMBER;
  3     v_num2     NUMBER;
  4     v_num3     NUMBER;
  5     v_run_id   BINARY_INTEGER; --    run    ID    generated    by    the    profiler
  6  BEGIN
  7     DBMS_PROFILER.START_PROFILER ('Optimizer    level    at    0');
  8
  9     FOR i IN 1 .. 1000000
 10     LOOP
 11        v_num1 := 1;
 12        v_num2 := i + i / 2 + SQRT (i);
 13        v_num3 := v_num1 + v_num2;
 14     END LOOP;
 15
 16     DBMS_PROFILER.STOP_PROFILER ();
 17
 18     SELECT min(runid)
 19       INTO v_run_id
 20       FROM plsql_profiler_runs
 21      WHERE run_comment = 'Optimizer    level    at    0';
 22
 23     DBMS_OUTPUT.PUT_LINE (
 24        'Optimizer    level    at    0,    run    ID    -    ' || v_run_id);
 25  END;
 26  /
Optimizer    level    at    0,    run    ID    -    1

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.00

5. 继续测试(Optimizer level at 1)

SQL> ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 1;

Session altered.

Elapsed: 00:00:00.00
SQL> /* Formatted on 2018/11/20 21:31:19 (QP5 v5.256.13226.35538) */
SQL> DECLARE
  2     v_num1     NUMBER;
  3     v_num2     NUMBER;
  4     v_num3     NUMBER;
  5     v_run_id   BINARY_INTEGER; --    run    ID    generated    by    the    profiler
  6  BEGIN
  7     DBMS_PROFILER.START_PROFILER ('Optimizer    level    at    1');
  8
  9     FOR i IN 1 .. 1000000
 10     LOOP
 11        v_num1 := 1;
 12        v_num2 := i + i / 2 + SQRT (i);
 13        v_num3 := v_num1 + v_num2;
 14     END LOOP;
 15
 16     DBMS_PROFILER.STOP_PROFILER ();
 17
 18     SELECT min(runid)
 19       INTO v_run_id
 20       FROM plsql_profiler_runs
 21      WHERE run_comment = 'Optimizer    level    at    1';
 22
 23     DBMS_OUTPUT.PUT_LINE (
 24        'Optimizer    level    at    1,    run    ID    -    ' || v_run_id);
 25  END;
 26  /
Optimizer    level    at    1,    run    ID    -    2

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.98

6. 继续测试(Optimizer level at 2)

SQL> ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 2;

Session altered.

Elapsed: 00:00:00.00
SQL> DECLARE
  2     v_num1     NUMBER;
  3     v_num2     NUMBER;
  4     v_num3     NUMBER;
  5     v_run_id   BINARY_INTEGER; --    run    ID    generated    by    the    profiler
  6  BEGIN
  7     DBMS_PROFILER.START_PROFILER ('Optimizer    level    at    2');
  8
  9     FOR i IN 1 .. 1000000
 10     LOOP
 11        v_num1 := 1;
 12        v_num2 := i + i / 2 + SQRT (i);
 13        v_num3 := v_num1 + v_num2;
 14     END LOOP;
 15
 16     DBMS_PROFILER.STOP_PROFILER ();
 17
 18     SELECT min(runid)
 19       INTO v_run_id
 20       FROM plsql_profiler_runs
 21      WHERE run_comment = 'Optimizer    level    at    2';
 22
 23     DBMS_OUTPUT.PUT_LINE (
 24        'Optimizer    level    at    2,    run    ID    -    ' || v_run_id);
 25  END;
 26  /
Optimizer    level    at    2,    run    ID    -    3

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.29

7. 查看由PL/SQL剖析器生成的数据

SQL> col runid for 9
SQL> col run_comment for a30
SQL> col line# for 99
SQL> col total_occur 9999999
SQL> col total_occur for 9999999
SQL> col total_time for 9999999999
SQL>   SELECT R.RUNID,
  2           R.RUN_COMMENT,
  3           D.LINE#,
  4           D.TOTAL_OCCUR,
  5           D.TOTAL_TIME
  6      FROM PLSQL_PROFILER_RUNS R, PLSQL_PROFILER_DATA D, PLSQL_PROFILER_UNITS U
  7     WHERE     R.RUNID = D.RUNID
  8           AND D.RUNID = U.RUNID
  9           AND D.UNIT_NUMBER = U.UNIT_NUMBER
 10           AND D.TOTAL_OCCUR > 0
 11  ORDER BY D.RUNID, D.LINE#;

RUNID RUN_COMMENT                    LINE# TOTAL_OCCUR  TOTAL_TIME
----- ------------------------------ ----- ----------- -----------
    2 Optimizer    level    at    1      9     1000001   130145331
    2 Optimizer    level    at    1     11     1000000   137672334
    2 Optimizer    level    at    1     12     1000000  1464785069
    2 Optimizer    level    at    1     13     1000000   182513305
    2 Optimizer    level    at    1     14           1           0
    2 Optimizer    level    at    1     16           1        4000
    3 Optimizer    level    at    2      9     1000001   169299824
    3 Optimizer    level    at    2     11     1000000           0
    3 Optimizer    level    at    2     12     1000000  1216234601
    3 Optimizer    level    at    2     13     1000000   216410666
    3 Optimizer    level    at    2     16           1        5013
    4 Optimizer    level    at    0      9     1000001   170080040
    4 Optimizer    level    at    0     11     1000000   244403943
    4 Optimizer    level    at    0     12     1000000  1646097380
    4 Optimizer    level    at    0     13     1000000   242038640
    4 Optimizer    level    at    0     14           1           0
    4 Optimizer    level    at    0     16           1        5017

8. 继续测试(对于空操作,两个优化级别的性能提高很明显)

SQL> -- Create test table
SQL> CREATE TABLE TEST_TAB
  2     (col1 NUMBER);

Table created.

Elapsed: 00:00:00.00
SQL>
SQL> -- Populate newly created table with random data
SQL> INSERT INTO TEST_TAB
  2  SELECT ROUND(DBMS_RANDOM.VALUE (1, 99999999), 0)
  3    FROM dual
  4  CONNECT by level < 100001;

100000 rows created.

Elapsed: 00:00:01.06
SQL> COMMIT;

Commit complete.

Elapsed: 00:00:00.00
SQL>
SQL> -- Collect statistics
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS (user, 'TEST_TAB');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.05
SQL>
SQL> -- Run the same code sample with different optimization levels
SQL> ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 1;

Session altered.

Elapsed: 00:00:00.00
SQL>
SQL> BEGIN
  2     FOR rec IN (SELECT col1 FROM test_tab)
  3     LOOP
  4        null; -- do nothing
  5     END LOOP;
  6  END;
  7  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.07
SQL>
SQL> ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 2;

Session altered.

Elapsed: 00:00:00.00
SQL>
SQL> BEGIN
  2     FOR REC IN (SELECT col1 FROM test_tab)
  3     LOOP
  4        NULL; -- do nothing
  5     END LOOP;
  6  END;
  7  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.06

9. 继续测试(对于插入操作,两个优化级别的性能提高不明显)

SQL> -- Create test table
SQL> CREATE TABLE test_tab1 (col1 NUMBER);

Table created.

Elapsed: 00:00:00.01
SQL>
SQL> -- Run the same code sample with different optimization levels
SQL> ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 1;

Session altered.

Elapsed: 00:00:00.01
SQL>
SQL> BEGIN
  2     FOR rec IN (SELECT col1 FROM test_tab)
  3     LOOP
  4        INSERT INTO TEST_TAB1 VALUES (rec.col1); -- populate newly created table
  5     END LOOP;
  6  END;
  7  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:05.10
SQL>
SQL> ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL = 2;

Session altered.

Elapsed: 00:00:00.00
SQL>
SQL> BEGIN
  2     FOR REC IN (SELECT col1 FROM test_tab)
  3     LOOP
  4        INSERT INTO TEST_TAB1 VALUES (rec.col1); -- populate newly created table
  5     END LOOP;
  6  END;
  7  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.87

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Oracle PL/SQLOracle数据库的编程语言,它允许开发人员编写存储过程、触发器、函数和包等数据库对象,以实现更高效、安全和可靠的应用程序。以下是一些Oracle PL/SQL必知必会的知识点: 1. PL/SQL基础语法:包括变量定义、控制结构、循环语句、异常处理等。 2. 存储过程:存储过程是一组SQL语句的集合,可以在其中定义变量、使用控制结构、调用其他存储过程等。 3. 触发器:触发器是一种特殊的存储过程,它会在数据库表上的特定事件发生时自动执行一些操作。 4. 函数:函数是一种可以接受输入参数并返回结果的代码块,它可以用于处理数据、计算等操作。 5. 包:包是一种可以封装存储过程、函数和变量的方式,它可以提供更好的代码管理和组织。 6. 游标:游标是一种可以遍历查询结果集的机制,它可以用于在PL/SQL中处理大量数据。 7. 动态SQL:动态SQL是一种可以在运行时构建和执行SQL语句的机制,它可以提供更大的灵活性和自由度。 8. 性能优化:在编写PL/SQL代码时需要注意性能问题,如尽量避免使用循环、减少数据库访问次数等。 9. 安全性:在编写PL/SQL代码时需要注意安全问题,如避免SQL注入攻击、对敏感数据进行加密等。 以上是Oracle PL/SQL必知必会的一些知识点,掌握它们可以帮助开发人员更好地使用Oracle数据库进行应用程序开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值