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

一、原理介绍:
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>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值