您的位置:首页 > 数据库

统计数据处理用数据库表的设计比较

2008-06-20 16:22 246 查看
统计数据处理用数据库的设计思考
统计数据处理过程大致分为:数据录入、数据审核和修改、数据汇总三个主要步骤或阶段,一般还包括数据的导入和导出。我们在设计用于统计数据处理的数据库时需要考虑各个阶段的用户需求特点,并进行相应的设计。
数据录入阶段:
这一阶段的特点是大量数据的录入,每次插入的数据量不一定很大,但有大量的提交。
数据审核和修改:
这一阶段的特点是批量数据的处理,产生审核错误清单,并随错误量的大小有相应数量的修改操作。
数据汇总:
这一阶段的特点是批量数据的处理,产生汇总结果。
数据的导入和导出:
导入阶段的特点是大量数据的导入,每次插入的数据量很大,但只有少量的提交。
数据导出一般从数据库中向外部文件输出数据,也是批量数据的处理。
用表格的方式说明如下:

提交
录入
审核
汇总
导入
除了业务的特点,我们还应考虑使用的dbms的特点
Oracle数据库的存储方式决定了它读取和批量插入速度较快,批量更新和删除较慢。
所以我们在设计时要尽量发挥Oracle数据库的长处,规避Oracle数据库的短处。
除此以外,我们还有许多可以调整的地方。例如:
1.表设计用较多字段但较少的记录还是较少字段但较多的记录。
2. 索引的采用
3. 表的存储参数
几种Oracle数据汇总的方法比较
我们在编写利用数据库存储数据的应用程序时,怎样加工数据有多种选择,一般来说,不外乎下面几种:SQL,数据库提供的存储过程,高级语言取出数据库的数据计算。
这些方法的优缺点不一定为人所知,下面我们以Oracle数据库为例,通过实验的方法来了解。
测试数据的产生,为尽量模拟实际统计数据处理的数据分布特点,我们采用了2种表格进行测试,
第一种 基本情况表,较多的字符型指标,指标的值长度差距较大,从1个字符到几十个字符
第二种 数据表 除了关键字,较多的数值型指标,指标的值基本上都在一个范围内,如15位有效数字
我们对第一种 基本情况表采用了第一次经济普查601表的结构和部分数据
第二种数据表用存储过程自动产生结构和数据
-- createtab创建一个含有指定数值型列的表,每个字段的有效数字可以指定
create or replace procedure createtab(colc IN NUMBER,PP IN NUMBER:=15,SS IN NUMBER:=2)
is
buf varchar(24000):='create table tcol'||to_char(colc)||'(x1 varchar(10),';
begin
for i in 1..colc-1
loop
buf:=buf||'v'||to_char(i)||' number('||to_char(PP)||','||to_char(SS)||'),';
end loop;
buf:=buf||'v'||to_char(colc)||' number('||to_char(PP)||','||to_char(SS)||'))';
execute immediate buf;
end;
-- inserttab插入一个含有指定数值型列的表,插入的行数可以指定,数值是随机的
create or replace procedure inserttab(rowc NUMBER,colc NUMBER)
is
buf varchar(24000):='insert into tcol'||to_char(colc)||' select level,';
begin
for i in 1..colc-1
loop
buf:=buf||'mod(level*DBMS_RANDOM.RANDOM,1e10),';
end loop;
buf:=buf||'mod(level*DBMS_RANDOM.RANDOM,1e10) from dual connect by level<='||to_char(rowc);
execute immediate buf;
end;
-- bat_ins将含有多个数值型列的表数据插入一个只有1个数值型列的表
create or replace procedure bat_ins(colc NUMBER)
as
begin
for i in 1..colc loop
EXECUTE IMMEDIATE 'insert into tcol1 select x1,'||i||',v'||i||' from tcol'||colc;
end loop;
commit;
end;
首先对20列数据进行测试
SQL> drop table tcol1;
Table dropped.
SQL> drop table tcol10;
Table dropped.
SQL> purge recyclebin;
Recyclebin purged.
SQL> set timi on
SQL> exec createtab(20);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.04
SQL> exec inserttab(20000,20);
PL/SQL procedure successfully completed.
Elapsed: 00:00:07.34
SQL> create table tcol1 as select x1,x1 x2,v1 from tcol20 where 1=2;
Table created.
Elapsed: 00:00:00.02
SQL> exec bat_ins(20);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.99
SQL> select x2, sum(v1) s1 from tcol1 group by x2 order by x2+0;
X2 S1
---------- ----------
1 1.8166E+12
2 -4.798E+11
3 -6.239E+11
4 -4.928E+11
5 8.3407E+11
6 4.0789E+11
7 2.3538E+11
8 -6.511E+11
9 -7.053E+11
10 -7.679E+11
11 6.6244E+11
12 -7.117E+11
13 3.8880E+11
14 -2.891E+11
15 -8.720E+11
16 1.1746E+11
17 3.4030E+11
18 -9.744E+11
19 2.1850E+12
20 -1.412E+11
20 rows selected.
Elapsed: 00:00:00.82
SQL> set pages 9999
SQL> select 'select ' from dual union all select 'sum(v'||level||') s'||level || ',' from dual connect by level<20 union all select 'sum(v20) s20 from tcol20' from dual;
'SELECT'
--------------------------------------------------------------------------------
select
sum(v1) s1,
sum(v2) s2,
sum(v3) s3,
sum(v4) s4,
sum(v5) s5,
sum(v6) s6,
sum(v7) s7,
sum(v8) s8,
sum(v9) s9,
sum(v10) s10,
sum(v11) s11,
sum(v12) s12,
sum(v13) s13,
sum(v14) s14,
sum(v15) s15,
sum(v16) s16,
sum(v17) s17,
sum(v18) s18,
sum(v19) s19,
sum(v20) s20 from tcol20
21 rows selected.
Elapsed: 00:00:00.01
SQL> set lines 132
SQL> select
2 sum(v1) s1,
3 sum(v2) s2,
4 sum(v3) s3,
5 sum(v4) s4,
6 sum(v5) s5,
7 sum(v6) s6,
8 sum(v7) s7,
9 sum(v8) s8,
10 sum(v9) s9,
11 sum(v10) s10,
12 sum(v11) s11,
13 sum(v12) s12,
14 sum(v13) s13,
15 sum(v14) s14,
16 sum(v15) s15,
17 sum(v16) s16,
18 sum(v17) s17,
19 sum(v18) s18,
20 sum(v19) s19,
21 sum(v20) s20 from tcol20;
S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
S13 S14 S15 S16 S17 S18 S19 S20
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1.8166E+12 -4.798E+11 -6.239E+11 -4.928E+11 8.3407E+11 4.0789E+11 2.3538E+11 -6.511E+11 -7.053E+11 -7.679E+11 6.6244E+11 -7.117E+11
3.8880E+11 -2.891E+11 -8.720E+11 1.1746E+11 3.4030E+11 -9.744E+11 2.1850E+12 -1.412E+11
Elapsed: 00:00:00.08
SQL>
再对40列和80列数据进行测试
SQL> drop table tcol1 purge;
Table dropped.
Elapsed: 00:00:00.08
SQL> drop table tcol20 purge;
Table dropped.
Elapsed: 00:00:00.06
SQL> exec createtab(40);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.04
SQL> exec inserttab(40000,40);
PL/SQL procedure successfully completed.
Elapsed: 00:00:27.92
SQL> create table tcol1 as select x1,x1 x2,v1 from tcol40 where 1=2;
Table created.
Elapsed: 00:00:00.03
SQL> exec bat_ins(40);
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.32
SQL> select x2, sum(v1) s1 from tcol1 group by x2 order by x2+0;
40 rows selected.
Elapsed: 00:00:05.24
SQL> select
… sum(v40) s40 from tcol40;
Elapsed: 00:00:00.32
SQL> drop table tcol1 purge;
Table dropped.
Elapsed: 00:00:22.15
SQL> drop table tcol40 purge;
Table dropped.
Elapsed: 00:00:05.31
SQL> exec createtab(80);
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.06
SQL> exec inserttab(80000,80);
PL/SQL procedure successfully completed.
Elapsed: 00:01:51.16
SQL> create table tcol1 as select x1,x1 x2,v1 from tcol80 where 1=2;
Table created.
Elapsed: 00:00:00.03
SQL> exec bat_ins(80);
PL/SQL procedure successfully completed.
Elapsed: 00:01:04.71
SQL> select x2, sum(v1) s1 from tcol1 group by x2 order by x2+0;
80 rows selected.
Elapsed: 00:00:35.63
SQL> select
… sum(v80) s80 from tcol80;
Elapsed: 00:00:01.62
SQL>
SQL> select mod(x1,2),x2, sum(v1) s1 from tcol1 group by mod(x1,2),x2 order by mod(x1,2), x2+0;
160 rows selected.
Elapsed: 00:00:28.94
SQL> select mod(x1,2),
… sum(v80) s80 from tcol80
group by mod(x1,2) order by mod(x1,2);
Elapsed: 00:00:01.70
由于随机数插入和从已有的表插入不具有可比性,插入时间仅供参考。
而汇总操作涉及表中所有数据的操作,这在实际数据处理中也经常遇到。

行*列
1列20列40列80列
20000*200.82 0.210.08 0.04
40000*405.24 0.740.32 0.14
80000*8035.63 2.911.62 0.53
从表中可以看出,随着数据量的增加,各种表的汇总时间基本都呈线性增长,只有1列的表增长稍快,当数据量增加到原来的4倍,处理时间的绝对值差5秒,数据量增加到原来的16倍,处理时间的绝对值差35秒,可以预测,当数据量进一步增加,两种表汇总时间的绝对值差还会增大。红色数据是Oracle 11g从位于AMD Opteron 8218(2.6GHz) 16CPU的Linux系统取得,绝对值差距没有HP-UX大,比例关系基本保持与HP-UX相同。
如果采用只有1个数值型列的表,如果不采用Oracle的分析函数,那么只能采用PL/SQL或java来进行表内审核,那么PL/SQL或java的处理效率和SQL相比如何呢?
测试环境一
Oracle 9.2.0.1 32bit
迅驰 1.6M 512M内存
Windows XP SP2
jdk版本1.3.1_01(Oracle 9.2自带)
数据库表 CJ601(第一次经济普查601表)
记录数 82320
记录平均长度390字节
总大小32104800字节
测试环境二
Oracle 9.2.0.8 64bit
HP 7410 1M*4 8G内存
jdk版本1.4.2.04(HP-UX自带)
数据库表 COL1 COL100
记录数 10000000 100000
字段数 2 101
记录平均长度(字节)15 589
总大小(字节)150000000 58900000
1首选SQL的分组函数方法
lt@IBMLT> select sum(z01_152/z01_151) from cj601;
SUM(Z01_152/Z01_151)
--------------------
361888727
已用时间: 00: 00: 00.02
SQL> select count(0), sum(v1) from col1;
COUNT(0) SUM(V1)
---------- ----------
10000000 1.6692E+14
已用时间: 00: 00: 07.64
SQL> select count(0), sum(v1) from col100;
COUNT(0) SUM(V1)
---------- ----------
100000 5000050000
已用时间: 00: 00: 00.58
2其次是手工编写PL/SQL脚本的方法
SQL> create or replace procedure
2 do_sum3( tablename in varchar2 )is
3 l_cnt number;
4 v1 cj601.z01_151%type;
5 v2 cj601.z01_152%type;
6 cursor cr is select z01_151,z01_152 from cj601; --只选择需要的字段
7 begin
8 l_cnt := 0;
9 open cr;
10 loop
11 fetch cr into v1,v2;
12 exit when cr%NOTFOUND;
13 l_cnt:= l_cnt + v2/v1;
14 end loop;
15 dbms_output.put_line( ' sum is '|| l_cnt );
16 close cr;
17 end;
18 /
过程已创建。
已用时间: 00: 00: 00.00
SQL> exec do_sum3('1');
sum is 361888726.5
PL/SQL 过程已成功完成。
已用时间: 00: 00: 01.05
如果把第6行改为 cursor cr is select * from cj601;
则运行时间增加到07.05秒,可见结果集记录字段个数越多,耗时越长。
在PL/SQL中使用Bulk Binds对性能有很大的提高,下面的PL/SQL过程比较了对同一个结果集采用二种方法的结果。
create or replace procedure
do_sumb( tablename in varchar2 )is
TYPE col1_tab IS TABLE OF col1%ROWTYPE;
col1_tabb col1_tab := col1_tab();
l_cnt number;
start_time number;
end_time number;
v1 col1.v1%type;
type b_t is table of col1.v1%type;
b_ b_t ;
cursor cr is select v1 from col100;
begin
l_cnt := 0;
start_time := DBMS_UTILITY.get_time;
open cr;
loop
fetch cr into v1;
exit when cr%NOTFOUND;
l_cnt:= l_cnt + v1;
end loop;
dbms_output.put_line( ' sum is '|| l_cnt );
close cr;
end_time := DBMS_UTILITY.get_time;
DBMS_OUTPUT.PUT_LINE('Conventional : '||to_char(end_time-start_time));
l_cnt := 0;
start_time := DBMS_UTILITY.get_time;
open cr;
loop
fetch cr BULK COLLECT into b_ LIMIT 10000;
exit when cr%NOTFOUND;
for i in 1 .. b_.count loop
l_cnt:= l_cnt + b_(i);
end loop;
end loop;
close cr;
dbms_output.put_line( ' sum is '|| l_cnt );
end_time := DBMS_UTILITY.get_time;
DBMS_OUTPUT.PUT_LINE('Bulk Collect : '||to_char(end_time-start_time));
end;
/
SQL> exec do_sumb('1');
sum is 5000050000
Conventional : 196
sum is 5000050000
Bulk Collect : 69

对记录数更多的表则更明显,修改cursor cr is select v1 from col1; 逐行获取和批量获取的时间比为4:1
SQL> exec do_sumb('1');
sum is 166919169175000
Conventional : 14884
sum is 166919169175000
Bulk Collect : 3514
PL/SQL 过程已成功完成。

3最后是手工编写通过JDBC访问Oracle的java程序的方法
import java.io.*;
import java.sql.*;
import java.math.BigDecimal;
/**
* oracle数据库thin协议下操作测试.
*/
public class test1
{
public static void main(String[] args)
{
Connection conn = null;
try
{
conn = getConnection();
String SQLSelect="select Z01_151,Z01_152 from cj601";
Statement stmt=conn.createStatement();
ResultSet rs = stmt.executeQuery(SQLSelect);
int i=0;
long sum1=0;
BigDecimal sum2= new java.math.BigDecimal("0");
long begin = System.currentTimeMillis();
while(rs.next())
{
sum2=sum2.add(rs.getBigDecimal("Z01_152").divide(rs.getBigDecimal("Z01_151"),15,2));
}
long current = System.currentTimeMillis();
stmt.close();
System.out.println("time="+String.valueOf(current-begin)+",count="+String.valueOf(i)+",sum1="+sum2.toString());
} catch (Exception e)
{
e.printStackTrace();
} finally
{
closeConnection(conn);
}
}
/**
* 获取数据库连接
*/
public static Connection getConnection() throws SQLException
{
String dbUrl = "jdbc:oracle:thin:@127.0.0.1:1521:ibmlt";
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
return DriverManager.getConnection(dbUrl, "lt", "lt");
}
/**
* 关闭数据库连接
*/
public static void closeConnection(Connection conn)
{
try
{
if(conn!=null)
{
conn.close();
}
} catch(Exception e)
{
e.printStackTrace();
}
}
}
C:/>C:/oracle/ora92/jdk/bin/javac -classpath C:/oracle/ora92/jdbc/lib/classes12.jar test2.java
C:/>java -cp C:/oracle/ora92/jdbc/lib/classes12.jar;. test2
time=3395,count=0,sum1=361888726.500000000000000
如果将SQL字符串改为“select * from cj601”,执行时间大大增加
C:/>java -cp C:/oracle/ora92/jdbc/lib/classes12.jar;. test1
time=20600,count=0,sum1=119986
如果SQL字符串不变,去掉除法运算,改为加法sum2=sum2.add(rs.getBigDecimal("v1")),执行时间有所缩短,
再改为与数据库字段无关的变量增加运算i=i+1,执行时间无明显变化,再进一步将循环体内语句清空,执行时间有所缩短,可见表扫描是最耗时的,各种数学运算费时差不多
C:/>java -cp C:/oracle/ora92/jdbc/lib/classes12.jar;. test1
time=1993,count=0,sum1=119986
如果使用jdk 1.4
将classpath中的classes12.jar改为ojdbc14.jar重新编译
由此可见,执行速度从快到慢的顺序是SQL、PL/SQL、java
当然,PL/SQL、java中也可以调用包含分组函数SQL语句直接汇总,执行时间和SQL差不多
SQL> create or replace procedure p_counttbl(t_name in varchar2) AUTHID CURRENT_USER as
2 v_ct number;
3 begin
4 execute immediate 'select sum(z01_152/z01_151) from cj601' into v_ct;
5 dbms_output.put_line(v_ct);
6 end;
7 /
过程已创建。
SQL> set timi on
SQL> set serveroutput on
SQL> exec p_counttbl('1');
361888726.5
PL/SQL 过程已成功完成。
已用时间: 00: 00: 00.05
同样,java程序也可相应修改SQLSelect="select sum(Z01_152/Z01_151) as sum0 from cj601"
和sum2=sum2.add(rs.getBigDecimal("sum0"));
C:/>C:/oracle/ora92/jdk/bin/javac -classpath C:/oracle/ora92/jdbc/lib/classes12.jar test3.java
C:/>java -cp C:/oracle/ora92/jdbc/lib/classes12.jar;. test3
time=30,count=0,sum1=361888726.5
对java程序也有一个参数可以用stmt.setFetchSize调整一次读取的记录数,但测试结果不明显。
一些对java的误解也通过测试澄清了,比如从数据库字段到java变量数据类型转换速度慢,我们把每步操作的时间都列出来,可见建立连接要费时间,其余主要就是循环时间,而不管循环内部是否读取数据库数据,时间都是差不多的。
/home/apras>javac -classpath /home/apras/weblogic/ojdbc14.jar testfoo.java
/home/apras>java -classpath /home/apras/weblogic/ojdbc14.jar:. testfoo
create conn time=844
create stmt time=845
create execsql time=847
create loop time=3274
time=3275,count=0,sum1=0
jdk的版本和jdbc jar的版本对运行速度也有细微的影响。就不再列举了。
几种Oracle数据审核的方法比较
用SQL语句的case when 实现一遍扫描列间审核

假定有79个审核关系,v2>v1,..v80>v79 ,每个审核关系给定一个序号分别是1-79
create table test_err(x1 varchar(10), ev number);

select 'insert into test_err select x1,' from dual union all
select 'case when v'||(level+1) ||'>v'||level ||' then '|| power(2,level) ||' else 0 end +' from dual connect by level<80 union all
select '0 from tcol80' from dual;

insert into test_err select x1,
case when v2>v1 then 2 else 0 end +
case when v3>v2 then 4 else 0 end +
case when v4>v3 then 8 else 0 end +
case when v5>v4 then 16 else 0 end +
case when v6>v5 then 32 else 0 end +
case when v7>v6 then 64 else 0 end +
case when v8>v7 then 128 else 0 end +
case when v9>v8 then 256 else 0 end +
:
:
case when v80>v79 then 604462909807314587353088 else 0 end +
0 from tcol80;
create or replace function n2b (x in number)
return varchar
is
n1 number(4);
f number:=0;
begin
n1:=(length(x)+1)*3.3219;
for i in 1 .. n1 loop
if bitand(x,power(2,n1-i))>0 then
f:=f+power(10,n1-i);
end if;
end loop;
return f;
end;
/
然后用n2b函数取各个2进制位表示某个序号的审核关系是否通过,或者用下面的字符串方式,用取字串判断某个审核关系是否通过
create table test_err1(x1 varchar(10), ev varchar(255));
insert into test_err select x1,
case when v2>v1 then 1 else 0 end ||
case when v3>v2 then 1 else 0 end ||
case when v4>v3 then 1 else 0 end ||
0 from tcol80;
用PL/SQL实现审核
create or replace procedure
test_chk( x in out number)is
l_cnt number;
vv tcol8%rowtype;
cursor cr is select * from tcol8;
begin
l_cnt := 0;
open cr;
loop
fetch cr into vv;
exit when cr%NOTFOUND;
if vv.v2>vv.v1 then
l_cnt:=l_cnt+2;
end if;
if vv.v3>vv.v2 then
l_cnt:=l_cnt+4;
end if;
end loop;
dbms_output.put_line( ' sum is '|| l_cnt );
close cr;
x:=l_cnt;
end;
/
和SQL方法一样,可以取返回的2进制位
以上方法都可以实现一遍扫描,审核多个审核关系同时把结果存储起来。
结论,如果可能,优先使用SQL语句解决问题,如果计算比较复杂,可以先在PL/SQL、java中调用SQL计算中间结果,然后用过程语言实现复杂的运算,再把结果输出或保存到数据库,这也是我们在开发应用程序中要注意的。
数据库系统运行的环境一般是具有大量CPU和内存资源的服务器,支持并行处理,SQL已经针对这些进行了优化,而自己编写程序实现并行有相当难度。
此外,符合SQL国际标准的数据库系统提供了更强大的SQL语句,比如分析函数的引入,它可以对记录间进行运算而只需要一次扫描;GROUPING SETS可以一次计算多个分组;这些都为我们尽量利用SQL语句提供了好的条件。
几种Oracle单位代码审核的方法比较
  全国组织机构代码由八位数字(或大写拉丁字母)本体代码和一位数字(或大写拉丁字母)校验码组成。
  1 本体代码采用系列(即分区段)顺序编码方法。
  2 校验码按下列公式计算:
C9=11-MOD(∑(Wi*Ci),11); i=1->8
  式中:MOD一表示求余函数;
  i一表示代码字符从左至右位置序号;
  Ci一表示第i位置上的代码字符的值;,如果Ci是数字,就是字面值,如'0'的值为0,如果Ci是大写字母,'A'开始算10,以此类推,如'Z'的值为35
  C9一表示校验码;
  Wi一表示第i位置上的加权因子,其数值如下表:
  i 1 2 3 4 5 6 7 8
  Wi 3 7 9 10 5 8 4 2

  当 MOD函数值为1(C9=10 )时,校验码应用大写拉丁字母X表示;当MOD函数值为0即(C9=11)时,校验码仍用0表示。
1.SQL调用PL/SQL存储过程
create or replace FUNCTION vcl(pid VARCHAR2) RETURN INT IS
TYPE it IS TABLE OF INT;
a it := it(3, 7, 9, 10, 5, 8, 4, 2);
x INT;
i NUMBER(2) := 0;
len NUMBER(2) := lengthb(pid);
sigma NUMBER(4) := 0;
BEGIN
IF len = 9 THEN
FOR i IN 1 .. 8 LOOP
x := ascii(substrb(pid, i, 1));
IF x >= 48 AND x <= 57 THEN
x := x - 48;
ELSIF x >= 65 AND x <= 90 THEN
x := x - 55;
ELSE
RETURN 0;
END IF;
sigma := sigma + x * a(i);
END LOOP;
IF MOD(sigma, 11) = 1 AND substrb(pid, 9, 1) = 'X' THEN
RETURN 1;
ELSIF to_char(mod(11 - MOD(sigma, 11),11))= substrb(pid, 9, 1) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
ELSE
RETURN 0;
END IF;
END vcl;
/
SQL> select sum(vcl('ABC'||(100000+level))) from dual connect by level<=50000;

SUM(VCL('ABC'||(100000+LEVEL)))
-------------------------------
4546

已用时间: 00: 00: 03.00

2.SQL调用Java存储过程
create or replace java source named jsv
as
public class jsv
{
public static int vc(byte[] code)
{
int[] w={3, 7, 9, 10, 5, 8, 4, 2};
int v=0;
for(int i=0;i<8;i++)
{
byte c=code[ i ];
if (!(c<'0' || c>'9') )
c-='0';
else if (!(c<'A' || c>'Z') )
c-='7';
else
return 0;
int t=c*w[ i ];//((1<<(8-i)) % 11);
v=v+t;
}
v=(11-(v%11))%11;
if(v<10)
v=v+'0';
else
v='X';
if(v==code[ 8 ])
return 1;
else
return 0;

}
}
/
create or replace function vcj(x varchar) return number
as
language Java Name
'jsv.vc(byte[]) return int';
/

SQL> set timi on
SQL> select sum(vcj('ABC'||(100000+level))) from dual connect by level<=50000;

SUM(VCJ('ABC'||(100000+LEVEL)))
-------------------------------
4546

已用时间: 00: 00: 00.09
在此特定的应用下,Java存储过程有更快的速度,但其他情况则不一定,比如log函数,Java快,random函数,DBMS_RANDOM.RAND快,另外Oracle XE不支持Java存储过程。
调用Java存储过程除了直接在sqlplus下输入.java源代码外,还可以在命令行用loadjava读入外部文件,执行效果相同。只是脚本在存入user_source表的名称区分大小写。loadjava还可以读入已编译的.class文件。
C:/>type jsv1.java
public class jsv1
{
public static int vc(byte[] code)
{
int v=0;
for(int i=0;i<8;i++)
{
byte c=code[ i ];
if (c>='0' && c<='9')
c-='0';
else if (c>='A' && c<='Z')
c-='7';
else
return 0;
int t=c*((1<<(8-i)) % 11);
v=v+t;
}
v=(11-(v%11))%11;
if(v<10)
v=v+'0';
else
v='X';
if(v==code[ 8 ])
return 1;
else
return 0;

}
}

C:/>loadjava -user lt/lt jsv1.java

C:/>sqlplus lt/lt

SQL> create or replace function vcj1(x varchar) return number
2 as
3 language Java Name
4 'jsv1.vc(byte[]) return int';
5 /

函数已创建。

SQL> set timi on
SQL> select sum(vcj1('ABC'||(100000+level))) from dual connect by level<=50000;

SUM(VCJ1('ABC'||(100000+LEVEL)))
--------------------------------
4546

已用时间: 00: 00: 01.03
2.SQL调用C外部过程
rac1->vi vc1.c

#include <string.h>
#include <stdio.h>
int vc(char code[])
{
/*if(strlen(code)!=9)
{
return 0;
} */
//strcpy(code,"HBA90021X");
int v=0;
int i=0;
for(i=0;i<8;i++)
{
char c=/*toupper*/(code[ i ]);
if(c>='0' && c<='9')
//(isdigit(c))
c-='0';
else if (c>='A' && c<='Z')
//(isalpha(c))
c=c-'7';//'A'+10;
else
return 0;
int t=c*((1<<(8-i)) % 11);
v=v+t;
}
v=(11-(v%11))%11;
if(v<10)
v=v+'0';
else
v='X';
if(v==/*toupper*/(code[8]))
return 1;
else
return 0;
}

~
"vc1.c" 36L, 510C written
rac1->cc -shared -o vc1.so vc1.c
rac1->cp vc1.so $ORACLE_HOME/bin
rac1->sqlplus lt/lt

SQL*Plus: Release 11.1.0.6.0 - Production on Wed Jun 18 14:27:55 2008

SQL> create or replace library c_vc1
2 as '$ORACLE_HOME/bin/vc1.so';
3 /

Library created.

SQL> CREATE OR REPLACE FUNCTION vcc1
2 (x varchar)
3 RETURN BINARY_INTEGER
AS LANGUAGE C
4 5 LIBRARY c_vc1
NAME "vc";
6 7 /

Function created.

SQL> set timi on
SQL> select sum(vcc1('MOD'||(200000+level))) from dual connect by level<=50000;

SUM(VCC1('MOD'||(200000+LEVEL)))
--------------------------------
4546

Elapsed: 00:00:02.83
SQL>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐