并发处理是一件头痛的事情
事实上真的并发了,系统也不能处理,因为从原理来讲,数据库在做 Insert , Update ,Delete,Tran 的时候会锁住数据表
使用 Sp_who 就可以看到那些表被锁住,对象是什么.
所以,当你在往一个表中进行大量的事务操作时,另一个请求只能等待.相信有数据库编程经验的朋友都有体验.
但在实际的业务过程中,又有这样的情况出现,例如下面一个例子:
有一个多分点的库存系统,每个分点都连到同一台SQL Server数据库上.每天的工作都需要出库入库,并立刻得知库存数量.
但它的商品记录形式又特别奇怪,他不能用数字来代替,只能用记录来代替.
例如:
某东西有二个,你不能把这个东西用2这样的数字代替,而必须要使用二两记录来代替,因为记录中有这个东西的唯一标识,换句话说,你可以理解成它有几十万个产品项目,而每个产品项目的数量永远为1
对于它的出入库操作也是必须要记录这个唯一的标识号,并算它这个月出入库的次数,最后判断它是否存在仓库中.
对于这种特殊的需求,我们分析得知,它必须要实时的得到仓库库存,并要求校验
这是一个问题,它大大加重了数据库的使用率
最重要的是,若干个分点同时操作,一定会有并发冲突的问题.请看计算库存的方法:
每次计算库存,我都搜索上次盘存时间(盘存时间不固定).然后计算每一次入库单(有N种类型,不同的类型不同的表示,还有直接与出库相关的),出库单(N种类型),销售单
公式如下:
入库单 - 出库单 - 销售单 = 库存
这样,从分析上来讲,我们需要使用一个事务来套这个公式,并得出计算结果输出到一个表中.
公式的方法决定了效率.我们怎么实现这个公式呢?
一开始我们这样做:
从上次盘存开始的入库单相关明细插入库存表
删除从上次盘存以来的出库单相关明细信息(中间还有一些复杂的关系)
删除从上次盘存以来销售相关明细(中间有一些复杂的运算)
OK,得到了结果,速度也很快,几万条记录在3秒中之类就可以算完,可以交付客户使用
可是我们忘了最重要的事....(中间还碰到许多怪事)
事务会锁住库存表,如果并发操作,将会使计算时间变成30秒或更长(3秒突然变成30秒...是不是太长了点)
如果多个事务一起叠加,后果更为严重...导至重启SQL SERVER服务器都无效
(最后,不管有没有并发计算,都成为了至少二分钟才能算出来,而且重启服务器都无效...最后怎么解决的呢?是把数据库的日志文件删除,然后再附加才解决的...真是奇怪啊,怎么与日志文件有关...不懂SQL SERVER的日志文件还有这种作用)
这样的程序肯定不行,太不稳定了...拿回来再改
事实上,我们需要的是尽可能的缩小锁表的时间,达到减少并发冲突,而每个分点最然用一个表,但又被不同的分点ID区分了
上面的过程改一改
从上次盘存开始的入库单相关明细插入临时表(#tmpTable)
从临时表删除从上次盘存以来的出库单相关明细信息(中间还有一些复杂的关系)
从临时表删除从上次盘存以来销售相关明细(中间有一些复杂的运算)
把临时表的内容插入到库存表
这样,锁表的时间只有0.1表,基本上不会发生冲突,就算发生,也不会出现恶性的冲突叠加
基本上完成了工作,目前已经运行半年,运算速度良好
所以,处理并发的根本就是,减少锁表的操作,多用临时表,另外,临时表一定要加主键,如果不加主键,速度会慢10倍左右
冲突叠加是一个比较恐怖的事情,3秒钟的运算,冲突一次变30秒,再冲突一次变1:30,再冲突一次变3:00...
后来不冲突,也恒定在2:00分钟左右才能计算完毕,关于最后这样的结果,我实在想不通,最后还是通过去掉LOG才解决的问题
更让我郁闷
不知道各位高手是如何处理这种情况的.