1. 结构
if exists (
select * from sysobjects
where id = object_id(N'[dbo].[np_DailyClose]')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[np_DailyClose]
GO
/****************************************************
过程名称:np_DailyClose
目的: 日结处理, 每日停业后必须做此工作,且只能做一次
创建日期: 作者:
修改日期:
返回代码:
-1 该日期已经做过日结
0 成功返回
涉及表:
1. tConfig
讨论:
1.
2.
*****************************************************/
CREATE proc np_DailyClose (
@dTransDate datetime -- 业务日期
)
as
…
return -- np_DailyClose
1. 结果的三种获得方法:可带回值的参数,return 值,select 返回记录集
2. 编写过程
1) 参数
2) 设置环境:显示设置一些环境开关:如加锁方法、set nocount on 等,否则因为用户环境不同,影响运行效果。
3) 框架:构思结构
4) 变量:统一放在前面,并注释。
5) 注释:注释和代码同步完成,保持一致。
6) 编写
7) 讨论记录
8) 测试
3. 必须考虑的问题
3.1 可读性
1) 逻辑清晰
2) 语句不要过于复杂,靠产生临时表过渡
3) 注释
4) 一屏可视,便于思考
5) 艺术感
3.2 效率
一种方法和语句的使用,必须考虑它的执行效率。注意以下问题:
1) 回避not in查询
2) 游标嵌套慎用
3) 使用索引:善于用索引,大大提高速度,在语句中有时需要显式说明。
4) 事务嵌套慎用。
结存程序一般30分钟以上,主要原因就是使用了not in 查询、游标嵌套、没有用索引。改造后同样数据量9秒就能完成。
4. 事务
1) 保持一致性所必需,必须有意识的考虑何时必须用事务。
2) 注意加锁特性,加锁属性开关状态。辽阳的例子,informix缺省加锁返回机制没有注意,造成偶尔死机,问题非常隐蔽。
3) 处理不当会带来系统死锁。
4) 仔细测试,否则的灾难将难以挽回。
5) 大量语句的事务推荐方法,将存储过程嵌在事务中,这样可以防止意外出错,造成死锁。见附件1。
5. 测试
5.1 测试环境的搭建,要保存一个对应的程序,因为不会轻易结束。见附件3。
5.2 编写和测试花一样的时间。
5.3 任何改动,都要测试。
5.4 叫真,不要想当然,因为还有系统软件的问题。如,错误号状态,是最后一个语句的错误,Sql 7.0的bug : 语句“if @@Error <>
5.5 调式工具
1) 灵活性,左连接,右连接。。。
2) 查询效率,条件语句的写法和顺序,自己掌握优化的主动权。
3) 保证正确,如update from累加修改时
update tMembers
set
iShareA = a.iShareA + b.iNewShare
from vMembers a, (select * from vMembers) b
where a.iMemberID = b.iUpMemberID
与
update tMembers
set
iShareA = a.iShareA + b.iNewShare
from tMembers a, (select * from vMembers) b
where a.iMemberID = b.iUpMemberID
区别:
使用视图时,左侧iShareA 和 右侧a.iShareA不是同一条记录;使用表时是一条。
iShareA = a.iShareA + b.iNewShare
2. 一些经验
2.1 善用临时表
1)避免多用户重名冲突。
2) 速度快,内存表。
3) 简化逻辑
4) 数据重用
2.2 回避not in 的技巧
--打标记bMark = 1(下一步对bMark = 0 的进行插入,这样速度快得多)
update #tWIV_Total set bMark = 1
from
#tWIV_Total a, tTWAccount b
where
a.cWhsID = b.cWhsID and a.cItemID = b.cItemID and a.cVendorID = b.cVendorID
-- 3)将bMark = 0 的关键字插入到tTWAccount中
insert into tTWAccount (cWhsID, cItemID, cVendorID, cCtrGrpID)
select
cWhsID,
cItemID,
cVendorID,
'' -- because not null
from
#tWIV_Total
where
bMark = 0
2.3 浮点数慎用
1) 会有芯片运算影响等问题
2) 累计求和时,舍入误差,经常产生“1分钱问题”。
3) 运行中产生意外结果,如判断 = 0,本来是0,可能判断结果不为0
2.4 统计数字作分母时,注意筛选条件加上<> 0限制,如
select iLevel, count(*) iCount
into #tChainLevelCount
from tMembers a, tChainLevel b
where
a.iLevel = b.iID
and a.cState = '0' and b.cType = 'A'
group by iLevel
having count(*) > 0