编写高效的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>
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>
相关文章推荐
- 在编写PL/SQL代码中使用SELECT语句时如何避免例外发生
- 在编写PL/SQL代码中使用SELECT语句时如何避免例外发生
- [Oracle]高效的PL/SQL程序设计(六)--%ROWTYPE的使用
- PL/SQL dev工具 使用for update-->Edit Date 时出错"These query results are not updateable,Include the ROWID to get updateable results."
- Oracle数据库编写PL/SQL代码经验谈
- 使用wrap和unwrap加密解密Oracle的PL/SQL对象(包,存储过程,函数等)代码
- Oracle数据库编程:使用PL/SQL编写触发器
- 使用PL/Scope分析PL/SQL代码
- 【转】PL/SQL编辑数据"这些查询结果不可更新,请包括ROWID或使用SELECT...FOR UPDATE获得可更新结果"处理
- 连载:编写高效代码(3)——使用更快的算法
- 编写健壮的PL/SQL代码(一):同字段同类型、%TYPE、SUBTYPE
- 使用PL/SQL Developer剖析PL/SQL代码
- 开发PL/SQL子程序和包及使用PL/SQL编写触发器、在JDBC中应用Oracle
- PL/SQL编辑数据"这些查询结果不可更新,请包括ROWID或使用SELECT...FOR UPDATE获得可更新结果"处理
- 在编写R语言代码时,怎样高效使用Sublime Text等编辑器
- 使用DBMS_HPROF进行PL/SQL代码探查
- PL/SQL 01 代码编写规则
- 使用 DBMS_PROFILER 定位 PL/SQL 瓶颈代码
- Oracle数据库编程:使用PL/SQL编写触发器
- [Oracle]高效的PL/SQL程序设计(一)--伪列ROWNUM使用技巧