您的位置:首页 > 数据库

编写高效的pl/sql代码一例——rowid的使用

2013-04-17 13:10 302 查看
一、原理介绍:
pl/sql的主要功能是处理表中的数据,效率的提高主要是在数据的查询上。我们已经知道索引可以提高查询效率。那么,索引的原理是什么呢?
例如,创建表employee(first_name varchar2, last_name varchar2),并在employee.last_name上创建索引ind_e1。我们可以把索引ind_e1看做是另外一张表,它包含2列(last_name, rowid)。
我们发出的sql:update employee set first_name='h' where last_name='g';先从索引ind_e1上查询到该行的rowid,然后再根据rowid直接定位到该行数据所在的数据块和行。
那么很明显,我们直接使用rowid作为查询条件,会比使用索引有更高的执行效率,因为这样会跳过从索引中查询rowid的步骤。下面是一个图示:
 

下面我们用一个例子来看一下:
 
二、相关测试:
--0.创建表test1(a varchar2),在test1.a上创建唯一索引ind_test1_a。
过程略
 
SQL> select a, rowid from test1;
 
A          ROWID

---------- ------------------

1          AAAHhNAALAAAAESAAA

2          AAAHhNAALAAAAESAAB

3          AAAHhNAALAAAAESAAC
 
--1.使用索引的执行计划:
SQL>  explain plan

  2   for

  3   update test1 set a = 22 where a = '2';
 
已解释。
 
SQL> @%oracle_home%\rdbms\admin\utlxpls
 
PLAN_TABLE_OUTPUT

----------------------------------------------------------------------
 
--------------------------------------------------------------------

| Id  | Operation            |  Name       | Rows  | Bytes | Cost  |

--------------------------------------------------------------------

|   0 | UPDATE STATEMENT     |             |       |       |       |

|   1 |  UPDATE              | TEST1       |       |       |       |

|*  2 |   INDEX UNIQUE SCAN  | PK_TEST1_A  |       |       |       |

--------------------------------------------------------------------
 
Predicate Information (identified by operation id):

---------------------------------------------------
 
PLAN_TABLE_OUTPUT

----------------------------------------------------------------------
 
   2 - access("TEST1"."A"='2')
 
Note: rule based optimization
 
已选择15行。
 
--2.使用rowid的执行计划:
SQL> explain plan

  2  for

  3  update test1 set a = 11 where rowid = 'AAAHhNAALAAAAESAAA';
 
已解释。
 
SQL> @%oracle_home%\rdbms\admin\utlxpls
 
PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------
 
---------------------------------------------------------------------------

| Id  | Operation                   |  Name       | Rows  | Bytes | Cost  |

---------------------------------------------------------------------------

|   0 | UPDATE STATEMENT            |             |       |       |       |

|   1 |  UPDATE                     | TEST1       |       |       |       |

|   2 |   TABLE ACCESS BY USER ROWID| TEST1       |       |       |       |

---------------------------------------------------------------------------
 
Note: rule based optimization
 
已选择10行。
 
三、使用方法
看起来使用rowid作为查询条件是一个不错的主意。但我们知道,不把某行数据查询出来,是不可能知道它的rowid的,那又在什么情况下使用呢?
 
情况1:先查询某行,再更新该行时。
有时候,我们需要查询出某条数据供界面显示,然后再对这行数据进行修改。那么,在查询时顺便找到该行的rowid,然后在更新时以rowid作为条件,会有更高的效率。
例如,我们先查询ic01:
select a.*, a.rowid into rec_ic01, r_ic01_rowid from ic01 a where aac001 = '13040100001' and aae002 = '200701';
那么下面这条更新语句会有更高的执行效率:
update ic01 set aic020=2000 where rowid=r_ic01_rowid;
相比较而言,下面这条更新语句效率就比较低了,它使用到了查询语句中的where条件:

update ic01 set aic020=2000 where aac001 = '13040100001' and aae002 = '200701';
 

情况2:隐含的使用rowid作为查询条件。
有时候,我们打开一个游标(可能有1000行),然后在循环中对每行进行更新处理,这时可以使用“where current of <cursor_name>”作为更新语句的查询条件。能起到和rowid同样的效果。
我们还是看一个例子吧:
SQL> set serveroutput on

SQL> DECLARE

  2    --定义游标,因为该游标中的数据需要更新,所以使用for update
  3    CURSOR cur_test1 IS

  4      SELECT *

  5        FROM test1

  6         FOR UPDATE;

  7    --定义记录类型,使用锚定。这样表test1变化时,不需要修改程序
  8    rec_test1 test1%ROWTYPE;

  9  BEGIN

 10    OPEN cur_test1;

 11    LOOP

 12      FETCH cur_test1 INTO rec_test1;

 13      EXIT WHEN cur_test1%NOTFOUND;

 14      --更新游标指针目前指向的test1的数据,使用current of cur_test1
 15      UPDATE test1

 16         SET a = a + 10

 17       WHERE CURRENT OF cur_test1;

 18    END LOOP;

 19    CLOSE cur_test1;

 20    COMMIT;

 21

 22    --我们使用隐式游标再打开一次,把结果显示出来看看
 23    FOR rec_test1_2 IN ( SELECT * FROM test1 ) LOOP

 24      dbms_output.put_line(rec_test1_2.a);

 25    END LOOP;

 26  END;

 27  /

11

12

13
 
PL/SQL 过程已成功完成。
 
SQL>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  PLSQL