`
sujianchinaouya
  • 浏览: 53596 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

愚人节之数据库设计规范

 
阅读更多

第一章 数据库逻辑设计原则

1.1 命名规范

1.1.1 表设计规范

1.1.1.1 表名

表名统一采用XX的命名方式。

1.1.1.2 表分区名

前缀为P_ 。分区名必须有特定含义的单词或字串。 例如 JXFZHP表的分区P_200601表示发站货票表第一季度的数据。

1.1.1.3 字段名

字段名称必须用大写字母,采用字段名称的汉字拼音缩写,不能用双引号包含。

1.1.1.4 主键名

前缀为PK_。主键名称应是前缀+表名+构成的字段名。如果复合主键的构成字段较多,则只包含第一个字段。表名去掉前缀。

1.1.1.5 外键名

前缀为FK_。外键名称是前缀+外键表名 + 主键表名 + 外键表构成的字段名。表名去掉前缀。

1.1.2 索引

1.1.2.1 普通索引

前缀为IDX_。索引名称应是 前缀+表名+构成的字段名。如果复合索引的构成字段较多,则只包含第一个字段,并添加序号。表名可以去掉前缀。

1.1.2.2 主键索引

前缀为IDX_PK_。索引名称为前缀+表名+构成的主键字段名,在创建表时候用using index指定主键索引属性。

1.1.2.3 唯一索引

前缀为IDX_UK_。索引名称为前缀+表名+构成的字段名。

1.1.2.4 外键索引

前缀为IDX_FK_。索引名称为前缀+表名+构成的外键字段名。

1.1.2.5 函数索引

前缀为IDX_FUNC_。索引名称为前缀+表名+构成的特征表达字符。

1.1.2.6 蔟索引

前缀为IDX_CLU_。索引名称为前缀+表名+构成的簇字段。

1.1.3 视图

前缀为V_,按业务操作命名视图。

1.1.4 存储过程

前缀为PROC_,按业务操作命名存储过程

1.1.5 触发器

前缀为Trig_,触发器名应是前缀 + 表名 + 触发器名。

1.1.6 函数

前缀为Func_,按业务操作命名函数

1.1.7 数据包

前缀为Pkg_,按业务操作集合命名数据包。

1.1.8 序列

前缀为Seq_,按业务属性命名。

1.1.9 表空间

1.1.9.1 公用表空间

前缀为TBS_,根据存储的特性命名,名称用大写字母,例如: TBS_DICT

1.1.9.2 专用表空间

TBS_<表名称>_nn。该表空间专门存储指定的某一个表,或某一表的若干个分区的数据

1.1.10 数据文件

<表空间名>nn.dbf nn =1234,…等。

1.2 命名约定

1.2.1 语言

命名不允许使用中文或者特殊字符,如用英文单词需使用对象本身意义相对或相近的单词,选择最简单或最通用的单词,不能使用毫不相干的单词来命名,当一个单词不能表达对象含义时,用词组组合,如果组合太长时,采用用简或缩写,缩写要基本能表达原单词的意义。当出现对象名重名时,是不同类型对象时,加类型前缀或后缀以示区别。

1.2.2 大小写

名称一律大写,以方便不同数据库移植,以及避免程序调用问题。

1.2.3 单词分隔

命名的各单词之间可以使用下划线进行分隔。

1.2.4 保留字

命名不允许使用SQL保留字。

1.2.5 命名长度

表名、字段名、视图名长度应限制在20个字符内(含前缀)

1.2.6 字段名称

同一个字段名在一个数据库中只能代表一个意思。比如telephone在一个表中代表“电话号码”的意思,在另外一个表中就不能代表“手机号码”的意思。不同的表用于相同内容的字段应该采用同样的名称,字段类型定义。

1.3 数据类型

1.3.1 字符型

固定长度的字串类型采用char,长度不固定的字串类型采用varchar2。避免在长度不固定的情况下采用char类型。如果在数据迁移等出现以上情况,则必须使用trim()函数截去字串后的空格。

1.3.2 数字型

数字型字段尽量采用number类型。

1.3.3 日期和时间

1.3.3.1 系统时间

由数据库产生的系统时间首选数据库的日期型,如DATE类型。

1.3.3.2 外部时间

由数据导入或外部应用程序产生的日期时间类型采用char类型,数据格式采用:YYYYMMDD HH24MISS

1.3.3.3 大字段

如无特别需要,避免使用大字段(blobcloblongtextimage)

1.3.3.4 唯一键

对于数字型唯一键值,尽可能用系列sequence产生。

1.4 设计

1.4.1 范式

如无性能上的必须原因,应该使用关系数据库理论,达到较高的范式,避免数据冗余,但是如果在数据量上与性能上无特别要求,考虑到实现的方便性可以有适当的数据冗余,但基本上要达到3NF。如非确实必要,避免一个字段中存储多个标志的做法。如11101表示5个标志的一种取值。这往往是增加复杂度,降低性能的地方。

1.4.2 表设计

1.4.2.1 逻辑段设计原则

1.4.2.1.1 Tablespace

  每个表在创建时候,必须指定所在的表空间,不要采用默认表空间以防止表建立在系统表空间上导致性能问题。对于事务比较繁忙的数据表,必须存放在该表的专用表空间中。

1.4.2.1.2 Pctused

  默认pctused导致数据库物理空间利用率非常低40%左右;对于update比较少或update不导致行增大的表,pctused可设置在6085之间;对于update能够导致行增大的表,update设置在4070之间

1.4.2.1.3 Storage

  1. Initial

  尽量减少表数据段的extents数量,initial的大小尽量接近数据段的大小64K128K,… 1M2M4M8M16M ,…,等按2的倍数进行圆整。例如表或分区数据段大小为28M,则initial32M

  2 Next

  表或分区扩展extents的大小,按上述方法进行圆整。当表或分区数据段无法按Initial接近值进行圆整的情况下,其大小可以按 Initial+Next进行圆整。此时,必须设置Minextents=2。例如:表或分区数据段大小为150M,则Initial=128M;Next=32MMinextents=2

  3 Minextents

  该参数表示表创建时候Extents的初始数量,一般取12

  4 Pctincrease

  表示每个扩展Extents的增长率,设置pctincrease=0能够获得较好的存储性能。

1.4.2.2 特殊表设计原则

1.4.2.2.1 分区表

  对于数据量比较大的表,根据表数据的属性进行分区,以得到较好的性能。箱管系统中的所有需要分区的表均以接收日期字段的范围进行分区。

1.4.2.2.2 聚蔟表

  如果某几个静态表关系比较密切,则可以采用聚蔟表的方法。

1.4.2.3 完整性设计原则

1.4.2.3.1 主键约束

  关联表的父表要求有主健,主健字段或组合字段必须满足非空属性和唯一性要求。对于数据量比较大的父表,要求指定索引段。

1.4.2.3.2 外键关联

  对于关联两个表的字段,一般应该分别建立主键、外键。实际是否建立外键,根据对数据完整性的要求决定。为了提高性能,对于数据量比较大的标要求对外健建立索引。对于有要求级联删除属性的外键,必须指定on delete cascade

1.4.2.3.3 NULL

  对于字段能否null,应该在sql建表脚本中明确指明,不应使用缺省。由于NULL值在参加任何运算中,结果均为NULL。所以在应用程序中必须利用nvl()函数把可能为NULL值的字段或变量转换为非NULL的默认值。例如:NVL(sale,0)

1.4.2.3.4 触发器

  触发器是一种特殊的存储过程,通过数据表的DML操作而触发执行,起作用是为确保数据的完整性和一致性不被破坏而创建,实现数据的完整约束。

  触发器的beforeafter事务属性的选择时候,对表操作的事务属性必须与应用程序事务属性保持一致,以避免死锁发生。在大型导入表中,尽量避免使用触发器。

1.4.2.4 注释

表、字段等应该有中文名称注释,以及需要说明的内容。

1.4.2.5 索引设计

  对于查询中需要作为查询条件的字段,可以考虑建立索引。最终根据性能的需要决定是否建立索引。对于复合索引,索引字段顺序比较关键,把查询频率比较高的字段排在索引组合的最前面。在分区表中,尽量采用local分区索引以方便分区维护。

  除非是分区local索引,否则在创建索引段时候必须指定指定索引段的tablespacestorage属性。

1.4.2.6 视图设计

  视图是虚拟的数据库表,在使用时要遵循以下原则:

1. 从一个或多个库表中查询部分数据项;

2. 为简化查询,将复杂的检索或字查询通过视图实现;

3. 提高数据的安全性,只将需要查看的数据信息显示给权限有限的人员;

4. 视图中如果嵌套使用视图,级数不得超过3;

5. 由于视图中只能固定条件或没有条件,所以对于数据量较大或随时间的推移逐渐增多的库表,不宜使用视图;可以采用实体化视图代替。

6. 除特殊需要,避免类似Select * from [TableName] 而没有检索条件的视图;

7. 视图中尽量避免出现数据排序的SQL语句。

1.4.2.7 包设计

  存储过程、函数、外部游标必须在指定的数据包对象PACKAGE中实现。存储过程、函数的建立如同其它语言形式的编程过程,适合采用模块化设计方法;当具体算法改变时,只需要修改需要存储过程即可,不需要修改其它语言的源程序。当和数据库频繁交换数据是通过存储过程可以提高运行速度,由于只有被授权的用户才能执行存储过程,所以存储过程有利于提高系统的安全性。

  存储过程、函数必须检索数据库表记录或数据库其他对象,甚至修改(执行InsertDeleteUpdateDropCreate等操作)数据库信息。如果某项功能不需要和数据库打交道,则不得通过数据库存储过程或函数的方式实现。在函数中避免采用DMLDDL语句。

  在数据包采用存储过程、函数重载的方法,简化数据包设计,提高代码效率。存储过程、函数必须有相应的出错处理功能。

1.4.2.8 安全性设计

1.4.2.9 管理默认用户

  在生产环境中,必须严格管理syssystem用户,必须修改其默认密码,禁止用该用户建立数据库应用对象。删除数据库测试用户scott

1.4.2.10 数据库级用户权限设计

  必须按照应用需求,设计不同的用户访问权限。包括应用系统管理用户,普通用户等,按照业务需求建立不同的应用角色。

  用户访问另外的用户对象时,应该通过创建同义词对象synonym进行访问。

1.4.2.11 角色与权限

  确定每个角色对数据库表的操作权限,如创建、检索、更新、删除等。每个角色拥有刚好能够完成任务的权限,不多也不少。在应用时再为用户分配角色,则每个用户的权限等于他所兼角色的权限之和。

1.4.2.12 应用级用户设计

  应用级的用户帐号密码不能与数据库相同,防止用户直接操作数据库。用户只能用帐号登陆到应用软件,通过应用软件访问数据库,而没有其它途径操作数据库。

1.4.2.13 用户密码管理

  用户帐号的密码必须进行加密处理,确保在任何地方的查询都不会出现密码的明文。  

第二章 备份恢复设计原则

1.5 数据库exp/imp备份恢复

  Oracle数据库的ExpImp提供了数据快速的备份和恢复手段,提供了数据库级、用户级和表级的数据备份恢复方式。这种方法一般作为数据库辅助备份手段。

1.5.1 数据库级备份原则

  在数据库的数据量比较小,或数据库初始建立的情况下采用。不适合7*24的在线生产环境数据库备份。

1.5.2 用户级备份原则

  在用户对象表数据容量比较小、或则用户对象初始建立的情况下使用。

1.5.3 表级备份原则

  主要在以下场合采用的备份方式:

  参数表备份

  静态表备份

  分区表的分区备份。

1.5.4 数据库冷备份原则

  数据库冷备份必须符合以下原则:

  数据库容量比较小。

  数据库允许关闭的情况。

1.6 Rman备份恢复原则

  这种方式适用于7*24环境下的联机热备份情形。

1.6.1 Catalog数据库

单独建立备份恢复用的数据库实例,尽可能与生产环境的数据库分开,确保catalog与生产数据库的网络连接良好。在9I系统使用良好的备份策略以可,支持完全使用控制文件保存catalog信息。

1.6.2 Archive Log

  设置Archive Log 的位置,确保存储介质有足够的空间来保留指定时间内archive log的总量。建设定期对RMAN进行全备份,删除冗余归档日志文件。

1.6.3 全备份策略

  对于大容量数据库,必须制定全备份策略方案,备份时对archive log进行转储,同时冷备份catalog 数据库。

1.6.4 增量备份策略

  对于大容量数据库,必须制定增量备份、累积备份和全备份的周期,备份时对archive log进行转储,同时冷备份catalog 数据库。

1.6.5 恢复原则

  采用Rman脚本进行数据库恢复。数据库恢复有以下几种:

1.6.5.1 局部恢复

  主要用于恢复表空间、数据文件,一般不影响数据库其他操作。

1.6.5.2 完全恢复

  数据库恢复到故障点,由catalog当前数据库决定。

1.6.5.3 不完全恢复

  恢复到数据库的某一时间点或备份点。

  恢复catalog数据库。

  恢复数据库control file

  恢复到数据库某一时间点。

  重设日志序列。

第三章 数据库设计工具

  统一使用sybase powerdesigner设计工具,在该工具上完成物理模型的设计。所有的数据库对象尽可能在物理模型上进行设计,而且每个物理模型都要有相应的文字描述。

所有的数据库对象变更以数据库物理模型为基准。为了避免字符敏感问题,产生的脚本以大写字母为标准。

设计完之后由powerdesigner生成建库和建表的SQL语句,并可生成数据库设计报告。

第四章 开发规范

1.7 SQL书写规范

1sql语句的所有表名、字段名全部大写。

2、连接符orinand、以及=、<=>=等前后加上一个空格。

3、对较为复杂的sql语句加上注释,说明算法、功能(主要针对用于外包的设计方案中)。

注释风格:注释单独成行、放在语句前面。

(1) 应对不易理解的分支条件表达式加注释;

(2) 对重要的计算应说明其功能;

(3) 过长的函数实现,应将其语句按实现的功能分段加以概括性说明;

(4) 每条SQL语句均应有注释说明(表名、字段名)。

(5) 常量及变量注释时,应注释被保存值的含义(必须),合法取值的范围(可选)

(6) 可采用单行/多行注释。(-- /* */ 方式)

4SQL语句的缩进风格

(1) 一行有多列,超过80个字符时,基于列对齐原则,采用下行缩进

(2) where子句书写时,每个条件占一行,语句令起一行时,以保留字或者连接符开始,连接符右对齐。

5、多表连接时,使用表的别名来引用列。

当在SQL语句中连接多个表时, 请使用表的别名,并把别名前缀加在每个列前面,这样就可以减少解析的时间并减少那些由列歧义引起的语法错误。

6where子句中不要使用函数(见性能优化建议中的相关内容)

7、在where子句中不要使用<>(见性能优化建议中的相关内容)

8、尽量使用变量绑定(Hibernate和报表除外)

这一条应特别注意,以前我们写的SQL语句多属于硬编码的方式,导致系统的性能比较低。关于如何在Java中使用绑定变量,见第四节《Java中使用绑定变量的方法》。

1.8 性能优化

1、 避免嵌套连接。例如:A = B and B = C and C = D

2、 通过ROWID访问表

开发中可以采用基于ROWID的访问方式情况,提高访问表的效率, , ROWID包含了表中记录的物理位置信息,ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系. 通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高。

2where条件中尽量减少使用常量比较,改用宿主变量,也就是使用绑定变量(采用Hibernate的模块不用考虑)。

3、系统可能选择基于规则的优化器,所以将结果集数据量小的表作为驱动表,也就是将数据量最小的表放在from的最后边。

4、大量的排序操作影响系统性能,所以尽量减少order bygroup by排序操作。

如必须使用排序操作,请遵循如下规则:

(1) 排序尽量建立在有索引的列上。

(2) 如结果集不需唯一,使用union all代替union

5SELECT子句中避免使用 * (count(*)除外)

当你想在SELECT子句中列出所有的COLUMN,使用动态SQL列引用 * 是一个方便的方法,不幸的是,这是一个非常低效的方法。 实际上。ORACLE在解析的过程中, 会将“*”依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间。

6、使用DECODE函数来减少处理时间

使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表。

例如:

SELECT COUNT(*)SUM(SAL) FROM EMP

WHERE DEPT_NO = 0020

AND ENAME LIKE ‘SMITH%’;

SELECT COUNT(*)SUM(SAL) FROM EMP

WHERE DEPT_NO = 0030

AND ENAME LIKE ‘SMITH%’;

你可以用DECODE函数高效地得到相同结果

SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,

COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,

SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,

SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL

FROM EMP WHERE ENAME LIKE ‘SMITH%’;

类似的,DECODE函数也可以运用于GROUP BY ORDER BY子句中。

7、用EXISTS替代IN

在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接。在这种情况下,使用EXISTS(NOT EXISTS)通常将提高查询的效率。

8、用EXISTS替换DISTINCT

当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT,一般可以考虑用EXISTS替换

例如:

低效:

SELECT DISTINCT DEPT_NO,DEPT_NAME

FROM DEPT D,EMP E

WHERE D.DEPT_NO = E.DEPT_NO

高效:

SELECT DEPT_NO,DEPT_NAME

FROM DEPT D

WHERE EXISTS ( SELECT ‘X’

FROM EMP E

WHERE E.DEPT_NO = D.DEPT_NO);

EXISTS 使查询更为迅速,因为数据库核心模块将在子查询的条件一旦满足后,立刻返回结果,因而节省查询所用时间,提高效率。

9、用UNION-ALL 替换UNION ( 如果有可能的话)

UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果,实际大部分应用中是不会产生重复的记录。

推荐方案:采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回,并不进行排序操作。

10、查询的WHERE过滤原则,应使过滤记录数最多的条件放在最前面。

11、任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。

12inor子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。

13、索引使用中的注意事项

(1) 尽量避免对索引列进行计算。如对索引列计算较多,请提请系统管理员建立函数索引。

采用函数处理的字段不能利用索引,如:

substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’

trunc(sk_rq)=trunc(sysdate) 优化处理:

sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)

(2) 尽量注意比较值与索引列数据类型的一致性,避免使用隐式类型转换。

(3) 对于复合索引,SQL语句必须使用主索引列

如果是在多个列上建立的复合索引,在where子句引用这些索引列中的一列时,只有在第一个列(leading column)被引用时,优化器才会选择使用该索引。

(4) 避免在索引列上使用IS NULLIS NOT NULL

判断字段是否为空一般是不会应用索引的,因为B树索引是不索引空值的。

推荐方案:用其它相同功能的操作运算代替,如

a is not null 改为 a>0 a>’’等。

(5) 对于索引的比较,尽量避免使用!=<>

不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。

推荐方案:用其它相同功能的操作运算代替,如

a<>0 改为 a>0 or a<0

a<>’’ 改为 a>’’

(6) 在索引列上避免使用NOT IN

NOT IN操作是强列推荐不使用的,因为它不能应用表的索引。

推荐方案:用NOT EXISTS 或(外连接+判断为空)方案代替。

(7) LIKE操作符

LIKE操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE ‘%5400%’ 这种查询不会引用索引,而LIKE ‘X5400%’则会引用范围索引。一个实际例子:用YW_YHJBQK表中营业编号后面的户标识号可来查询营业编号 YY_BH LIKE ‘%5400%’ 这个条件会产生全表扫描,如果改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’ 则会利用YY_BH的索引进行两个范围的查询,性能将会大大提高。

(8) 使用索引引起的where语句效率

使用AND语句时行数多的放在前面

使用OR语句时,行数多的放在后面

(9) 查询列和排序列与索引列次序保持一致

1.9 Java中使用绑定变量的方法

为了不重复解析相同的SQL语句(因为解析操作比较费资源,会导致性能下降),在第一次解析之后,ORACLESQL语句及解析后得到的执行计划存放在内存中。这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享。因此,当你执行一个SQL语句(有时被称为一个游标)时,如果该语句和之前的执行过的某一语句完全相同,并且之前执行的该语句与其执行计划仍然在内存中存在,则ORACLE就不需要再进行分析,直接得到该语句的执行路径。ORACLE的这个功能大大地提高了SQL的执行性能并大大节省了内存的使用。使用这个功能的关键是将执行过的语句尽可能放到内存中,所以这要求有大的共享池(通过设置shared buffer pool参数值)和尽可能的使用绑定变量的方法执行SQL语句。

如果不使用绑定变量,可能要花大量的时间来解析查询,而不是执行它们。这将显著减少应用系统最终能够支持的用户数,部分原因是执行硬解析会增加资源的消耗量,但更主要的因素是在硬解析SQL语句的过程中对库缓存锁(library cache latch)和共享池锁(shared pool latch)的争用。随着用户数的增加,硬解析的SQL也会增加,对这两种锁的争用将呈几何级数增长,结果就是应用系统不可扩展。

SQL语句中,绑定变量是一个占位符。例如,为了查询员工号为123的员工的信息,可以查询:1select * from emp where empno=123;另外,也可以查询:2select * from emp where empno=:empno

在一个典型的OLTP系统中,查询员工123一次,可能再也不会查询,以后将查询员工456,员工789等。如果像语句1)中那样使用硬编码量(常量),那么每次查询都是一个新查询,即在数据库共享池中以前没有过的查询。每次查询必须经过分析、限定(名称解析)、安全检查、优化等等,简单地说,执行的每条语句在每次执行时都将必须经过编译。

在第二个查询2)中使用了绑定变量:empno,它的值在查询执行时提供。查询经过一次编译后,查询方案将存储在共享池中,可以用来检索和重用。在性能和可伸缩性方面,这两者的差异是巨大的,甚至是惊人的。

从上所述,很明显看出,分析一个带有硬编码量的语句将比重用一条已分析过的查询方案花费更长的时间和消耗更多的资源,不明显的是前者将减少系统所能支持的用户数量。很明显,部分原因是由于增加资源消耗量,但更主要的因素是在解析sql语句的过程中对共享池中锁存器(latch)的争用。

通过下面的两个小程序我们可以看出其中的差别,其中程序NoBind.java没有使用绑定变量,程序UseBind.java使用了绑定变量。

程序NoBind.java

/*

* This sample can be used to demostrate if you don't use bind variable.
* You will find more than one sql statement was parsed.
*/

// You need to import the java.sql package to use JDBC
import java.sql.*;
import oracle.jdbc.*;

// We import java.io to be able to use the i/o Class
import java.io.*;

class NoBind
{
public static void main(String args[])
throws SQLException, IOException
{
// Load the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:

demo","scott","tiger");

// Create a statement

Statement stmt = conn.createStatement();
for(int i=1;i<=5;i++)
{
ResultSet rset = stmt.executeQuery("select hisal from salgrade where grade="+i);
while (rset.next())
{
System.out.println(rset.getString(1));
}
// close the result set
rset.close();
}
// close the statement and connect
stmt.close();
conn.close();

}
}

程序UseBind.java
/*
* This sample can be used to demostrate how to use bind variable.
* Just run it and select the sql statement from the v$sql,you will
* find only one sql statement was parsed.
*/

// You need to import the java.sql package to use JDBC
import java.sql.*;
import oracle.jdbc.*;

// We import java.io to be able to use the i/o Class
import java.io.*;

class UseBind
{
public static void main(String args[])
throws SQLException, IOException
{
// Load the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn = DriverManager.getConnection(

"jdbc:oracle:thin:@127.0.0.1:1521: demo","scott","tiger");

// Create a PreparedStatement

PreparedStatement pstmt = conn.prepareStatement("select hisal from

salgrade where grade=?");
for (int i=1;i<=5;i++)
{
// use the setXX() method
pstmt.setInt (1,i);
ResultSet rset = pstmt.executeQuery();
while (rset.next())
{
System.out.println(rset.getString(1));// print the first column
}
// close the result set
rset.close();
}
// close the statement and connect
pstmt.close();
conn.close();

}
}

上面两个程序都是通过scott/tiger登录,从salgrade表中检索5条数据,然后在终端上打印出来,不同之处在于第一个程序使用硬编码量,通过拼字符串的方式来构造sql语句,第二个程序使用了绑定变量,先使用一个占位符代替实际数值,然后再通过setInt()方法给占位符赋值。

执行程序NoBind.java后,通过查询v$sql视图可以发现,Oracle解析了5条不同的sql语句,如下:

SQL> select sql_text from v$sql where sql_text like 'select hisal from%';

SQL_TEXT
-------------------------------------------------------------------------------

select hisal from salgrade where grade=1
select hisal from salgrade where grade=4
select hisal from salgrade where grade=2
select hisal from salgrade where grade=5
select hisal from salgrade where grade=3

重新启动数据库,然后再执行程序UseBind.java后,通过查询v$sql视图可以发现,Oracle只解析了1sql语句,如下:

SQL> select sql_text from v$sql where sql_text like 'select hisal from%';

SQL_TEXT
-------------------------------------------------------------------------------

select hisal from salgrade where grade=:1

通过上述测试可以看出,通过使用绑定变量,应用程序提交的相似的sql语句的执需要解析一次,就可以重复使用,这非常有效,这也是Oracle数据库要求使用的工作方式。不仅使用较少的资源,而且可以减少锁存(latch)时间,降低锁存(latch)次数,这将提高应用系统性能,并且大大提高可伸缩性。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics