begin
len1 := length(p_string);
v_string := replace(p_string, ' ', ' ');
len2 := length(v_string);
while (len2 < len1)
loop
len1 := len2;
v_string := replace(v_string, ' ', ' ');
len2 := length(v_string);
end loop;
return v_string;
end;
/
SQL> select squeeze1('azeryt hgfrdt r')
2 from dual
3 /
azeryt hgfrdt r
Elapsed: 00:00:00.00
SQL> select squeeze2('azeryt hgfrdt r')
2 from dual
3 /
azeryt hgfrdt r
Elapsed: 00:00:00.01
SQL> select squeeze3('azeryt hgfrdt r')
2 from dual
3 /
azeryt hgfrdt r
Elapsed: 00:00:00.00
那么,如果每天要调用该空格替换cāo作几千次呢?我们构造一个接近现实负载的环境,下面的
代码将建立一个用于测试的表并填入随机数据,已检测上面三个函数是否有xìng能差异:
create table squeezable(random_text varchar2(50))
/
declare
i binary_integer;
j binary_integer;
k binary_integer;
v_string varchar2(50);
begin
for i in 1 .. 10000
loop
j := dbms_random.value(1, 100);
v_string := dbms_random.string('U', 50);
while (j < length(v_string))
loop
k := dbms_random.value(1, 3);
v_string := substr(substr(v_string, 1, j) || rpad(' ', k)
|| substr(v_string, j + 1), 1, 50);
j := dbms_random.value(1, 100);
end loop;
insert into squeezable
values(v_string);
end loop;
上面的脚本在测试表中建立了10 000条记录(决定SQL 语句要执行多少次时,这是数字比较适
中)。要执行该测试,运行下列语句:
我运行这个测试时,关闭了所有头信息(headers)和屏幕的显示。禁止输出可确保结果反映的
是替换空格算法所花费的时间,而不是显示结果所花费的时间。这些语句会执行多次,以确保
不受缓存(caching)的影响。
表2-2显示了在测试机上的运行结果。
表2-2:处理10 000条记录中空格所花的时间
commit;
end;
/
select squeeze_func(random_text)
from squeezable;
函数机制时间
squeeze1
用PL/SQL 循环处理字符0.86 秒
尽管都在1秒内完成了10 000次调用,但squeeze2的速度是squeeze1的1.8 倍,而squeeze3
则是它的2.2 倍。为什么呢?原因很简单,因为SQL 函数比PL/SQL“离核心更近”。当函数只偶
尔执行一次时,xìng能差异微乎其微,但在批处理程序或高负载的OLTP 服务器中xìng能差异就非
常明显。
总结:代码喜欢SQL内核——离核心越近,它就运行得越快。
只做必须做的
Doing
Only
What
Is
Required
开发者使用count(*)往往只是为了测试“是否存在”。这通常是由以下的需求说明引起的:
如果存在满足某条件的记录
那么处理这些记录
用代码直接实现就是:
当然,在90% 的情况下,count(*) 是完全不必要的,正如上面的例子。要对多项记录进行cāo
作,直接做即可,不必用count(*)。即使一个cāo作对任何记录都没有影响,也没有关系,不用
count(*)没有什么不好。而且,即使要对未知的记录进行复杂处理,也能通过第一个cāo作就确定
并返回受影响的记录——要么通过特殊的API (例如PHP 中的mysql_affected_rows()),要么
采用系统变量(Transact-SQL 中为@@ROWCOUNT,PL/SQL 中为SQL%ROWCOUNT),若使
用内嵌式SQL,则使用SQL通讯区(SQL Communication Area,SQLCA)的特殊字段。有时,
squeeze2 Instr() + ltrim()
0.48 秒
squeeze3 循环调用replace() 0.39 秒
select count(*)
into counter
from table_ncom
where <certain_condition>
if (counter > 0) then
可以通过函数访问数据库然后直接返回要处理的记录数,例如JDBC 的executeUpdate()方法。
总之,统计记录数极可能意味着重复全部搜索,因为它对相同数据处理了两次。
此外,如果是为了更新或chā入记录(常使用count检查键是否已经存在),一些数据库系统会提
供专用的语句(例如Oracle 9i 提供MERGE 语句),其执行效率要比使用count高得多。
总结:没必要编程实现那些数据库隐含实现的功能。
SQL
语句反映业务逻辑
SQL Statcomnts Mirror Business Logic
大多数数据库系统都提供监控功能,我们可以借此查看当前正在执行的语句及其执行的次数。
同时,必须对有多少个“业务单元(business units)”正在执行心里有数——例如待处理的订单、
需处理的请求、需结账的客户,或者业务管理者了解的任何事情。我们应检查上述语句活动和
业务活动的数量关系是否合理(并不要求绝对精确)。换言之,如果客户数量一定,那么数据库
初始化活动的数量是否与之相同?如果查询custcomrs 表的次数比同一时间正在处理的客户量
多20 倍,那一定是某个地方出了问题,或许该查询对表中相同记录做了重复(而且多余)的
访问,而不是一次就从表中找出了所需信息。
总结:检查数据库活动,看它是否与当时正进行的业务活动保持合理的一致xìng。
把逻辑放到查询中
Program Logic into Queries
在数据库应用程序中实现过程逻辑(procedural logic)的方法有几种。SQL语句内部可实现某
种程度上的过程逻辑(尽管SQL语句应该说明做什么,而不是怎么做)。即便内嵌式SQL的宿主
语言(host language)非常完善,依然推荐尽量将上述过程逻辑放在SQL语句当中,而不是宿
主语言当中,因为前一种做法效率更高。过程xìng语言(Procedural language)的特点在于拥有
执行迭代(循环)和条件(if ... then ... else 结构)逻辑的能力。SQL不需要循环能力,因为它
本质上是在cāo作集合,SQL只需要执行条件逻辑的能力。
条件逻辑包含两部分——IF和ELSE。要实现IF的效果相当容易——where子句可以胜任,困难
的是实现ELSE 逻辑。例如,要取出一些记录,然
松语文学免费小说阅读_www.16sy.com