设为首页 收藏本站
查看: 719|回复: 0

[经验分享] 探讨SQL Server并发处理队列数据不阻塞解决方案

[复制链接]

尚未签到

发表于 2017-7-12 19:42:23 | 显示全部楼层 |阅读模式
前言
  之前对于并发这一块确实接触的比较少,自从遇到现在的老大,每写完一块老大都会过目一下然后给出意见,期间确实收获不少,接下来有几篇会来讲解SQL Server中关于并发这一块的内容,有的是总结,有的是学习,若有错误见解请批评性指出。

SQL Server并发处理队列数据问题
  在我们的项目中对于购买产品的用户会对应分配卡密,同时会更新其卡密的状态为已使用,所以当出现并发时此时我们不加以控制会导致同一个卡号和密码被不同的用户所使用,这样的情况是不能允许的,此时我们迫切需要解决对卡密使用后的更新和产生的并发。所以有了此文的产生。我们接下来来创建测试表。



CREATE TABLE Test (
Id    INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
Other VARCHAR(100))
GO
  接下来我们插入十条测试数据



DECLARE  @counter INT
SELECT @counter = 1
WHILE (@counter <= 10)
BEGIN
INSERT INTO Test
(Other)
SELECT 'other action' + CAST(@counter AS VARCHAR)
SELECT @counter = @counter + 1
END
DSC0000.png

  接下来我们打开两个会话运行如下SQL语句:



DECLARE @queueid INT
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
  此时我们看到打开的两个会话会同时处理相同的行。
DSC0001.png

DSC0002.png

  如上则不是我们想要的结果,此时我们再来在如上基础上加一个更新锁,然后SQL Server查询引擎会不允许其他读取者来获取更新锁,此时将能够有效的处理对应对应的行记录,但是会造成阻塞,如下:



DECLARE @queueid INT
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test WITH (updlock)
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
DSC0003.png

DSC0004.png

  上述虽然能解决更新问题,但是此时会造成阻塞,一旦并发量比较大此时将造成长时间阻塞,当前正在执行的更新会话必须等待另外一个更新会话执行完毕同时释放更新锁。此时为了解决阻塞问题,在SQL Server中通过添加READPAST关键字来告诉SQL Server引擎一旦遇到被锁住的行,你就跳过吧不用理会,所以不会再造成阻塞问题。此时最终的代码将变成如下:



DECLARE @queueid INT
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test WITH (updlock)
BEGIN TRAN TRAN1
SELECT TOP 1 @queueid = Id
FROM Test WITH (UPDLOCK, READPAST)
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)
WAITFOR DELAY '00:00:10'
DELETE FROM Test
WHERE Id = @queueid
COMMIT
  通过UPDLOCK+READPAST结合使用将对于处理并发更新时,就像处理队列数据一样,但是不会造成阻塞,此时将给予我们最好的性能。我们结合上述所讲,来查询出数据并删除对应数据且,不会出现重复删除情况且不会导致阻塞,此时代码将变成如下:



SET NOCOUNT ON
DECLARE @queueid INT  
WHILE (SELECT COUNT(*) FROM Test WITH (updlock, readpast)) >= 1
BEGIN
BEGIN TRAN TRAN1  
SELECT TOP 1 @queueid = Id  
FROM Test WITH (updlock, readpast)  
PRINT 'processing queueid # ' + CAST(@queueid AS VARCHAR)  
WAITFOR DELAY '00:00:10'  
DELETE FROM Test
WHERE Id = @queueid
COMMIT
END
DSC0005.png

DSC0006.png


总结
  本文我们探讨产生并发在SQL Server中如何不处于阻塞并且得到较好的性能,对于那种秒杀情况,这种方案不失为一种解决方案,请问你有何高见?

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-393274-1-1.html 上篇帖子: SQL Server 存储过程中处理多个查询条件的几种常见写法分析,我们该用那种写法 下篇帖子: SQL SERVER 运维日记-数据库备份
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表