青云Oracle(3)

2019-04-17 14:58

Oracle自身为什么使用的nvarchar2较少,我觉得可能有两个原因: a. Oracle的字符集很复杂,有的时候设置不好,就容易导致nvarchar2的数据是乱码;

b. Oracle对Nvarchar2的效率优化可能没有varchar2做的好;就像我们很多时候推

荐是使用pls_integer 代替integer;

当然,nvarchar2的优点也是很明显的,比如定义varchar2(5),只能录入2个汉字加一个字母,nvarchar2(5)可以录入5个汉字;

1.7.2很多前台程序,对VARCAHR2支持的更好些;

我举个简单的例子

Create table xxx ( a varchar2(5), b varchar2(5 char),c

nvarchar2(5));

然后通过我们最常用toad工具插入数据

前台程序有点傻,把Unicode类型的长度翻倍了,所以干脆就用传统的vachar2算了,这样前台程序可以做的更人性化点;

我的oracle工具可以明确的看到B,C的长度是10;

接着我用了一款由c#开发的oracle工具,荷兰devart公司做的OraDevelper Studo 测试,也得到相同效果;

2.PL/SQL 的常用技巧和注意点

2.1绑定变量

这个问题是个“重中之重”的问题,对于我们这些做OLTP(联机事务处理,特点是并发多,事务短)系统的朋友来说,尤为要重视这个问题;我见过周围太多的了,都没有意识到这个问题的重要性;我自己能做到“洁身自好”,基本在项目开发的时候,不用任何硬编码,但如果合作者大量使用了硬编码,就让我“前功尽弃”;这个问题一直是我心中的痛; 什么绑定变量?举个简单的例子:

Select * from tab1 wher f1=:f1

这样的语句就是绑定变量的语句,:f1对应的值可以为任何值,比如’a’,’ab’,’abc’; 无论为什么值,内部只要解析一次, 如果不用绑定变量,就是硬编码: 比如:

Select * from tab1 wher f1=’a’

Select * from tab1 wher f1=’ab’ Select * from tab1 wher f1=’abc’

这3句话,Oracle就要解析3次,而且随着f1这个字段值不断地变化,解析的次数是“无限”的;

什么是解析?简单的说分两步:

1. 判断sql语句是否合法,表或字段等信息数据字典是否正确等; 2. 生成执行计划树,这个步骤是关键,就比如每天早上从家到公司上班,

有很多条路线,选择一条性价比最好的路线; 如果是硬编码,每次执行SQL的时候,这个解析都得重做一遍,这个是很大的“资源浪费”; oracle 所有执行的语句都要放在服务器的一个内存里(SGA的shared_pool), 如果是绑定变量的SQL,变量无论怎么变化,它在这个内存里只占用一次,而如果是硬编码,where条件的值每变化一次,就会申请一个新的内存块存储,oracle这么做的目的是:“好心”让你这个SQL的解析以后有机会再被用到,避免了重复解析,而硬编码机会很难有机会复用,所以把oracle的好心当做驴肝肺了; 还有更严重的问题,硬编码除了上面说的影响自己的运作速度,还影响别人运作;就像小时候上学,自己上课不想听讲,可以自己趴桌子上睡觉,那大不了是自己学不到东西,而如果大声讲话,就会影响到别人,这个是不能容忍的,硬编码这一点上是最糟糕的;因为“内存”是有大小限制的,如果硬编码申请太多,就会把“别人”那些解析好的SQL“挤走”,别人就没法复用它,需要重新解析;

同时每次申请新的内存保存SQL,也会产生一种锁,叫闩(latch)锁,是最轻量级的一种锁,但会影响并发性,在高并发的情况下,硬编码甚至会导致服务器game over;这不是危言耸听,是TOM大师的的警世之言;

这个是TOM大师的原话:“使用绑定变量

如果我要写一本书谈谈如何构建不可扩缩的Oracle应用,肯定会把\不要使用绑定变量\作为第一章和最后一章的标题重点强调。这是导致性能问题的一个主要原因,也是阻碍可扩缩性的一个重要因素。Oracle将已解析、已编译的SQL连同其他内容存储在共享池(shared pool)中,这是系统全局区(System Global Area ,SGA)中一个非常重要的共享内存结构。第4章将详细讨论共享池。这个结构能完成\平滑\操作,但有一个前提,要求开发人员在大多数情况下都会使用绑定变量。如果你确实想让Oracle缓慢地运行,甚至几近停顿,只要根本不使用绑定变量就可以办到。 ”

下面一幅图,展示了同一个查询,用绑定变量和硬编码两种方法对SGA中共享池(shared_pool)这块内存的影响

2.2不要动不动就用游标

在开发过程中,经常看到procedure/package里充满了一坨坨的显式游标,而且很多地方都是2,3嵌套,游标看上去是“万金油”,但最好还是在不得已的时候再用,很多初学者或者SQL经验技巧不够好的人, 都喜欢在是实现业务逻辑的时候,脑子里马上想到了游标,因为游标很类似于前台程序开发中while/for 循环;不过如果深入研究过oracle的运作机制后,就不会肆无忌惮的使用游标了;

我认为游标的缺点有以下几处:

a. 容易有并发脏数据,游标打开后,这些记录集在一个个的循环处理的

这段时间内,它所对应的表的数据可能别别人修改,也就是说,游标的数据时可能是5秒前的数据,执行一个游标的逻辑处理后,整个5秒钟内,游标的记录集的真实数据可能发生了很多变化;这样处理的逻辑就会出问题,这样的问题,并不是“程序逻辑”造成的,所以一旦出现数据问题,从“程序逻辑”上分析,是找不到原因的。简单的说,这个就是类似“刻舟求剑”的误区,对于动态变化的东西,我们在先前的某个时间段得到的东西是不能作为依据的;

当然,对于稍微了解oracle锁机制的人,知道for update 的处理 比如,定义一个游标 select * from tabel1 where … for update

其实,知道在游标里使用for update ,只能说前进了一下步,但它也不能滥用,滥用for update 也会有很多弊端; a.1 滥用for update ,会加大了锁的几率,对高并发系统有串行影响; a.2 有的时候for update使用不好,会在程序内部报错;

a.3 有的时候没法加for update ,比如稍微复杂些的sql,多表关联,带聚合函数等,就没法加上for update;

b. 很多技巧都可以代替游标,举个简单的例子,比如要求出库100件;

仓库库存分布

货位 数量

1 20

2 50 3 40 4 45

…..

这种情况,很多人都是用游标做循环去取数据; 其实,大可不必:

我们通过分析函数 sum(..) over (order by..) ; 对库存分布虚拟两个个累计和列出来即可:

比如:

仓库库存分布

货位 数量 累加数量 前一个累加数量(累加数量-当前数量) 1 20 20 0 2 50 70 20

3 40 110 70 (70~110之间的满足100) 4 45 155 110 …..

这样,我们就不必要做循环一条条的去判断,只要

判断累加数量<=100 and前一个累加数>100 即可,于是马上分析1,2,3货位都出库;1,2全出,3货位出:出库要求(100)- 前一个累计(70)=30个 Pl/sql代码可以这样写:

Insert into 出库任务

select 货位, case 累加数量<=100 then数量 else 100-前一个累加数量 end as 出库数量 from 仓库库存分布 where 累加数量<=100 and前一个累加数>100

一句话搞定的事情,何必用游标去循环慢慢折腾;就像今年春节晚会,郭冬临的小品,一句话的事情,搞那么复杂干嘛;效率低就不跟你计较了,关键是简单的


青云Oracle(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:18版高考语文二轮复习考前三个月第四轮基础组合练21

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: