高效访问数据库

查询的识别

要养成为程序和关键模块加注释的习惯,在SQL中插入注释有助于辨别查询在程序中的位置。

这些注释在插叙哦是非常有用。注释也有助于判断单独应用对服务器造成的负载有多大。

oracle的dbms_application_info包,它支持48字节的模块明后名称、32个字节的动作名称和64个字节的客户信息,在oracle环境下,可以利用这个程序包记录在哪个应用正在执行,以及他在何时正在做什么。

保持数据库连接稳定

尽量减少分别连接数据库次数。

将预更新的数据填入数组,这样就尽可能减少了程序和数据库核心间的交互次数,从而使性能产生了另一次飞跃。

原因:

1.在于数据库连接是很重的操作,消耗资源很多。

客户端与远程服务器的监听程序建立联系;

监听程序要么创建一个进程或线程来执行数据库核心程序,要么直接或间接的把客户请求传递给已存在的服务器进程,这取决于此服务器是否为共享服务器。

除了这些系统操作(创建进程和线程并开始执行)之外,数据库系统还必须为每个session建立新环境,以跟踪它的行为。建立新session前,DBMS还要执行登录触发器,还要初始化存储过程和程序包。上面这些还不包括客户端进程和服务器进程之间要完成的握手协议。正因为如此,连接池等保持永久数据库连接的技术对性能才如此重要。

2程序(甚至包括存储过程)和数据库之间的交互也有开销。

即使数据库连接已经建立且扔未中断,程序和DBMS核心之间的上下文切换也有代价。

 

物化视图是某时间点的数据副本。

保持数据库Schema稳定

在应用程序中使用数据定义语言(DDL)建立、修改或删除数据对象,是很差的方式。

DDL的作用是以核心数据库的数据字典为基础的,数据字典是所有数据库操作的中心,所以任何对数据字典的操作都会引起全局枷锁,对系统性能影响巨大。唯一可接受的DDL操作是对表的truncate(清空)操作,它能极快地清空表的所有数据(记住,truncate table不可通过回滚回复)。

不应再程序中进行数据库对象的建立、修改及删除等操作,虽然设计应用时要考虑这些问题。

 

直接操作实际数据

永久表可以设置非常复杂的存储选项,而临时表不能。临时表的索引可能不是最优的,因此,查询临时表的语句效率比永久表的差。另外,查询之前必然先为临时表填入数据。

如果一定要用临时表,应确保数据库知道哪些表是临时的。

用SQL处理集合

SQL完全基于集合(set)来处理数据。

一次将大批量数据的处理分割成多次小块处理效率低:

1.占用过多的空间保存原始数据,以备事务回滚。

2.万一修改失败,回滚消耗过长的实践。

不要认为在进行大规模修改操作时,应该在操作数据的代码中有规律的多安排些commit命令。严格从实践的角度讲,“从头开始重做”比“确定失败发生的时间和位置接着已提交部分重做”要容易的多,简单的多,也快的多。

 动作丰富的SQL语句

避免SQL中引入“过程逻辑”的主要原因:

1.数据库访问,总会跨多个软件层,甚至包括网络层。

即使没有网络访问,也会涉及进程间通讯;额外的存取访问意味着更多的函数调用、更大的宽带,以及更长的等待时间。

2.在SQL中引入过程逻辑,意味着性能和维护问题应该由你的程序承担。

慎用自定义函数

优化器对自定义函数的代码苏能为力。

简洁的SQL语句

oracle的bulk collect子句,一次性将两个值放到数据中,

select slosure_date

bulk sollect into dtPerStaArray

from tperrslt

where relt_period in ('1' || to_char(Param_dtAcc,'MM'),

                                '9' || to_char(Param)dtAcc,'MM"))

order by rslt_period;

放到两个变量中。

select max(decode(subset(reslt_period,1,1),
          '1',closure_date,
          to_date('14/10/1066','DD/MM/YYYY'))),
       max(deocode(substr(reslt_period,1,1),
       '9',closure_datte,
       to_date(14/10/1066','DD/MM/YYYY'))),
       into dtPerSta,dtPerClosure
       form tperrslt
       where fiscal_year=to_char(Param_dtAcc,'YYYY')
       and rslt_period in ('1' || to_char(Param_dtAcc,'MM'),
                          '9' || to_char(Param_dtAcc,'MM'));

SQL的进攻式编程

高效访问数据库_第1张图片

高效访问数据库_第2张图片

精明的使用异常

重复键的探索,唯一性如何保证?

我们几乎总是建立一个唯一索引,每次向该索引增加一个键时,都要检查是否违反了该唯一性索引。然而,建立索引项需要记录物理地址,于是就要求先将记录插入表,后将索引项插入索引。如果违反了此约束,数据库会取消不完全的插入,并返回违反约束的错误信息。

上述这些操作开销巨大,但最大的问题是,整个处理必须围绕个别异常展开,于是我们必须“从个别记录的及年度进行思考”,而不是“从数据集出发进行思考”,这与关系数据库理论完全背道而驰。多次违反此约束会导致性能严重下降。

translate
语法:TRANSLATE(char, from, to)
用法:返回将出现在from中的每个字符替换为to中的相应字符以后的字符串。
            若from比to字符串长,那么在from中比to中多出的字符将会被删除。
            三个参数中有一个是空,返回值也将是空值。
举例:SQL> select translate('abcdefga','abc','wo') 返回值 from dual;
            返回值
            -------
            wodefgw
分析:该语句要将'abcdefga'中的'abc'转换为'wo',
            由于'abc'中'a'对应'wo'中的'w',
            故将'abcdefga'中的'a'全部转换成'w';
            而'abc'中'b'对应'wo'中的'o',
            故将'abcdefga'中的'b'全部转换成'o';
            'abc'中的'c'在'wo'中没有与之对应的字符,
            故将'abcdefga'中的'c'全部删除;
            简单说来,就是将from中的字符转换为to中与之位置对应的字符,
            若to中找不到与之对应的字符,返回值中的该字符将会被删除。
            在实际的业务中,可以用来删除一些异常数据,
            比如表a中的一个字段t_no表示电话号码,
            而电话号码本身应该是一个由数字组成的字符串,
            为了删除那些含有非数字的异常数据,
            就用到了translate函数:delete from a,
                      where length(translate(trim(a.t_no),
                                            '0123456789' || a.t_no,
                                            '0123456789')) <> length(trim(a.t_no));

 

你可能感兴趣的:(Oracle)