博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

CLEANER

如果你的工作,机器也可以做。那总有一天,你也要变成机器。
   yuechaotian.cublog.cn
关于作者  
name:yuechaotian
employment:coder
age:25
from:NEU
about me:a retardate
email:yuechaotian(at)gmail.com
msn:yuechaotian(at)hotmail.com

我的分类  




PL/SQL collection(5)— 联合数组
联合数组的语法如下:

 

TYPE table_type_name IS TABLE OF datatype [ NOT NULL ]

       INDEX BY index_type;

 

我们只看一下 index_type,其它的比较简单。

 

Oracle9i Database Release 2 之前,只能使用 binary_integer 作为索引下标。从 Oracle9i Release 2 开始,可以使用 binary_integer 及其所有的子类型、varchar( n ),或者 %type 锚定的列或变量(当然,也必须是这两种类型之一)。也就是说,现在支持的索引类型如下:

 

INDEX BY BINARY_INTEGER;

INDEX BY PLS_INTEGER;

INDEX BY POSITIVE;

INDEX BY NATURAL;

INDEX BY SIGNTYPE;

INDEX BY VARCHAR2(32767);

INDEX BY table.column%TYPE;

INDEX BY cursor.column%TYPE;

INDEX BY package.variable%TYPE;

INDEX BY package.subtype;

 

 

1. VARCHAR2 下标

 

有时候,使用 varchar2 类型的索引来存储数据,会使我们的编码变得更加简洁。我们举个小例子,来看一下它的用法:

 

SQL> set serveroutput on

SQL> declare

  2    type taa_salary is table of number(10,2) index by varchar2(20);

  3    aa_salary taa_salary;

  4    v_name varchar2(20);

  5  begin

  6    aa_salary('yuechaotian') := 3300;

  7    aa_salary('guoguo') := 3600;

  8    aa_salary('oratea') := 3200;

  9    aa_salary('hot_dog') := 3300;

 10    v_name := aa_salary.first;

 11    while v_name is not null loop

 12      dbms_output.put_line( 'Name: ' || v_name || ' | Salary: ' || aa_salary(v_name) );

 13      v_name := aa_salary.next(v_name);

 14    end loop;

 15  end;

 16  /

Name: guoguo | Salary: 3600

Name: hot_dog | Salary: 3300

Name: oratea | Salary: 3200

Name: yuechaotian | Salary: 3300

 

PL/SQL 过程已成功完成。

 

SQL>

 

 以 binary_integer 作为索引的联合数组,是按照数字大小来排序的。而从上面的例子看,以 varchar2 作为索引的联合数组,似乎是按照ASCII码的顺序来排列的,当然这只是猜测,有待进一步验证。不过以 varchar2 作为索引的联合数组,很少会重视排序的情况。

 

 

2. 数值下标

 

大部分时候,我们还是使用数值作为联合数组的下标。使用时,注意一下各种下标的范围即可:

 

INDEX BY clause

Minimum value

Maximum value

    INDEX BY BINARY_INTEGER

-231 + 1

231 - 1

    INDEX BY PLS_INTEGER

-231 + 1

231 - 1

    INDEX BY NATURAL

0

231 - 1

    INDEX BY POSITIVE

1

231 - 1

    INDEX BY SIGNTYPE

-1

1

    INDEX BY VARCHAR(N)

Any string within specified length

Any string within specified length

 
我们还记得联合数组是可以稀疏存储数据的吧?对于用习惯传统的数组的人,可能会觉得稀疏数组有点怪异,它有什么用呢?我举一个系统应用的例子:
 
做 PL/SQL 开发时,我们会发现自己一次又一次地编写并执行相同的查询 SQL,很多时候,这些数据都是“静态”的(数据不变)。如果在用户的一个会话期内这些数据没有变化,那么为什么我们不能在内存中把这些数据保存起来并直接使用呢?要知道,我们一次次地执行的这个 SQL,其执行计划已经在共享池中了,它所对应的数据也很可能已经在 SGA 的 buffer cache 中了。我们还用得着一次一次地软解析这个 SQL,再从 buffer cache 中获取数据,并返回到该会话的 PGA 中吗?
 
如果你的业务处理是这样的:在用户的一个会话期内,只从该“静态”表中获取一次数据,保存到该会话的 PGA 中,并在后继操作中多次使用该数据。那么你可以考虑使用集合。而 Oracle 所提供的这三种集合方法里,联合数组是最适合了,因为它具有稀疏的特性,我们可以灵活地使用这个功能。我们一步一步地说明什么时候适合使用稀疏的联合数组:
 
在一个 MIS 系统中,使用表 RYJBXX 保存人员的基本信息。在某个逻辑复杂的业务中,我需要对每一个人进行处理,处理时需要从表 RYJBXX 中获取每个人的基本信息。我可以每次获取一条记录,就像下面的伪码:

 

DECLARE
  rec_ryjbxx ryjbxx%ROWTYPE;
  ...
BEGIN
  ...
  FOR ... LOOP
    ...
    SELECT *
      INTO rec_ryjbxx
      FROM ryjbxx
     WHERE rybh = v_rybh; 
    ...
  END LOOP;
  ...
END;

 

如果需要处理 3w 人,那么这个查询 SQL 就得执行 3w 次。虽然它用上了索引,这个 SQL 执行很快,但 3w 次执行的时间累加后就很可观了。这时候可以考虑使用集合实现。我们学过批量绑定,很容易想到的就是采用这种方法,下面用联合数组重写这段伪码:

 

DECLARE
  TYPE taa_ryjbxx IS TABLE OF ryjbxx%ROWTYPE INDEX BY PLS_INTEGER;
  aa_ryjbxx taa_ryjbxx;
  ...
BEGIN
  ...
  SELECT *
    BULK COLLECT INTO aa_ryjbxx
    FROM ryjbxx;
 
  FOR ... LOOP
   
  END LOOP;
  ...
END;

 
是的,它执行很快,似乎是最完美的解决方法了。那么,我们考虑一个问题:在后继的编码中,我如何使用联合数组 aa_ryjbxx 中的数据呢?比如我要使用编号为‘001’的人员的年龄,如何从 aa_ryjbxx 中获取?除了采用循环一个一个地比较,我没有更好的办法!看来批量绑定又增加了使用上的复杂度。
 
为什么不试试联合数组的稀疏特性呢?它可以稀疏地存储数据,而且断开的下标之间是不会浪费空间的。比如我可以使用个人编号作为下标,来实现这个功能:

 

DECLARE

  TYPE taa_ryjbxx IS TABLE OF ryjbxx%ROWTYPE INDEX BY PLS_INTEGER;

  aa_ryjbxx taa_ryjbxx;

  ...

BEGIN

  ...

  FOR rec_ryjbxx IN ( SELECT * FROM ryjbxx ) LOOP

    aa_ryjbxx( rec_ryjbxx.grbh ) := rec_ryjbxx;

  END LOOP;

 

  FOR ... LOOP

    -- 可以用个人编号作为下标,使用集合的各种方法。比如 EXISTS

    IF aa_ryjbxx.EXISTS( v_grbh ) THEN

      ...

    END IF;

  END LOOP;

  ...

END;

 

那么在后继的编码中,我可以很方便地取出相应人员的基本信息了。不要忘记集合有很多的方法可以使用。

关于使用集合缓存数据的方法,做一点总结:

* 这种方法是内存与磁盘IO之间的平衡。每个会话都有它自己的集合数据的拷贝,存放在各自的 PGA 中。如果有100个用户并发,那么将会有100份集合数据的拷贝,你得考虑机器的内存是否够用。

* 在以下情况中,可以考虑使用该技术:在多用户应用中的小的“静态”表;用户只访问一个大的“静态”表的一小部分数据;在批处理程序中处理大表(即只有1个会话占用大量内存的情况)。

 发表于: 2008-05-21,修改于: 2008-05-27 17:34 已浏览458次,有评论0条 推荐 投诉

  网友评论

  发表评论



Copyright © 2001-2006 ChinaUnix.net All Rights Reserved

感谢所有关心和支持过ChinaUnix的朋友们
页面生成时间:0.23494

京ICP证041476号