高性能的SQL过程是数据库开发人员所追求的,我将不断把学到的,或在实际开发中用到的一些提高SQL过程性能的技巧整理出来,温故而知新.
1,在只使用一条语句即可做到时避免使用多条语句
让我们从一个简单的编码技巧开始。如下所示的单个 INSERT 行序列:
INSERT INTO tab_comp VALUES (item1, price1, qty1);ITPUB个人空间se%Pt9`)W
INSERT INTO tab_comp VALUES (item2, price2, qty2);ITPUB个人空间6]d'g{sf,gCN5h
INSERT INTO tab_comp VALUES (item3, price3, qty3);可以改写成:
INSERT INTO tab_comp VALUES (item1, price1, qty1),
nTb.^ r4?}(M0 (item2, price2, qty2),
'sh)nu/ZB]#^0执行这个多行 INSERT 语句所需时间大约是执行原来三条语句的三分之一。孤立地看,这一改进看起来似乎是微乎其微的,但是,如果这一代码段是重复执行的(例如该代码段位于循环体或触发器体中),那么改进是非常显著的。
类似地,如下所示的 SET 语句序列:
SET A = expr1;
!D8p&|7Q_0SET B = expr2;ITPUB个人空间"B cf&Sl zv
SET C = expr3;可以写成一条 VALUES 语句:
VALUES expr1, expr2, expr3 INTO A, B, C;
如果任何两条语句之间都没有相关性,那么这一转换保留了原始序列的语义。为了说明这一点,请考虑:
SET A = monthly_avg * 12;
B I8CL;eP*].q0SET B = (A / 2) * correction_factor;将上面两条语句转换成:
VALUES (monthly_avg * 12, (A / 2) * correction_factor) INTO A, B;
不会保留原始的语义,因为是以“并行”方式对 INTO 关键字之前的表达式进行求值的。这意味着赋给 B 的值并不以赋给 A 的值为基础,这是原始语句预期的语义。
oI7^?D02,从多个 SQL 语句到一个 SQL 表达式
Y8m [/_%|y2a5tB/o0跟其它编程语言一样,SQL 语言提供了两类条件构造:过程型(IF 和 CASE 语句)和函数型(CASE 表达式)。在大多数环境中,可使用任何一种构造来表达计算,到底使用哪一种只是喜好问题。但是,使用 CASE 表达式编写的逻辑不但比使用 CASE 或 IF 语句编写的逻辑更紧凑,而且更有效。
请考虑下面的 SQL PL 代码片段:
IF (Price <= MaxPrice) THENITPUB个人空间VFRP6d pQB7|AH
INSERT INTO tab_comp(Id, Val) VALUES(Oid, Price);
]|]}|(`$o#Q&z&?0ELSE
p m%G/Jmk H0 INSERT INTO tab_comp(Id, Val) VALUES(Oid, MaxPrice);ITPUB个人空间0Em.zQ#C$y(|&p
END IF;IF 子句中的条件仅用于决定将什么值插入 tab_comp.Val 列中。为了避免过程层和数据流层之间的上下文切换,可利用 CASE 表达式将相同的逻辑表示成一个 INSERT 语句:
INSERT INTO tab_comp(Id, Val)
Mh1T9o^%}5~0 VALUES(Oid,
/c0tE&h M`s3D v0 CASEITPUB个人空间DaX / X6l
WHEN (Price <= MaxPrice) THEN PriceITPUB个人空间l P({)zg lM
ELSE MaxPrice
}J/FM:@1h:x*h0值得注意的是,CASE 表达式可在任何希望有标量值的上下文中使用。特别地,可在赋值符号的右边使用它们。例如:
IF (Name IS NOT NULL) THEN
f.Q8TI VE(WA0 SET ProdName = Name;ITPUB个人空间J4C:~3O [$|
ELSEIF (NameStr IS NOT NULL) THEN
?*~n7^y|k4~6b0 SET ProdName = NameStr;
rn-]8cFN,d%rN0ELSEITPUB个人空间ac2Uf2t2Q_�i
SET ProdName = DefaultName;
:wfJ2k1tM.~#d0END IF;可以改写成:
SET ProdName = (CASEITPUB个人空间W:yZ!U)P6^/d
WHEN (Name IS NOT NULL) THEN NameITPUB个人空间P;~e[t9w)o
WHEN (NameStr IS NOT NULL) THEN NameStr
3@ @yRzEzWX0 ELSE DefaultNameITPUB个人空间hNQ/Ko8p;A
END);实际上,这个特殊的示例有一个更好的解决方案:
SET ProdName = COALESCE(Name, NameStr, DefaultName);
3、使用 SQL 的一次处理一个集合语义
$EG2|DAk'y0诸如循环、赋值和游标之类的过程化构造允许我们表达那些只使用 SQL DML 语句是不可能表达的计算。但是,当我们拥有一些可以随意使用的过程语句时,即使我们手头的计算实际上仅使用 SQL DML 语句就可表达,但转换成过程语句还是有风险的。正如我们以前提到的,过程计算的性能与使用 DML 语句表达的同一个计算的性能相比会慢几个数量级。请考虑下面的代码片段:
DECLARE cur1 CURSOR FOR SELECT col1, col2 FROM tab_comp;ITPUB个人空间 Q1B&J