并发数高时,数据库数据会混乱,好像和参数化查询有关

时间:2022-09-08 13:59:29
并发数高时,数据库数据会混乱,好像和参数化查询有关
现在有个操作是这样的
update table set  name=@name,tel=@tel where id=@id
并发数不高时一切正常,当有个以每秒几千次的并发数来操作这条时
比如他一直传入参数
@name='1'
@tel='2'
@id=1
然后有个人也要更新这个表当他传入
@name='a'
@tel='b'
@id=2
时,他的数据有时可能会变成
name='1',tel='2',id=2
但他正常的数据应该是name='a',tel='b',id=2
这个是不是因为数据库内对参数化处理时,因为第一个在不断的访问,造成参数混乱了
我想如果只是一条不带参数的SQL update table set  name='1',tel='2' where id=2它是肯定不出问题的,但用参数化时就出问题了,不知道大家有没有出现过这种情况,有没有什么办法可以解决
这个是数据库内部机制问题吗,还是我的写法问题,麻烦高手帮忙解答一下,小弟感激不尽 并发数高时,数据库数据会混乱,好像和参数化查询有关

42 个解决方案

#1


你查询的时候用了with nolock?

#2


这个是没用好事务的问题。不是数据库机制的问题。

参数化也好,还是原来的标准语句,都需要良好的事务支持。脏读,幻影啥的,都是要考虑的问题。

并发高,如果允许脏读发生,那基本都没啥性能上的干扰。
如果严格的控制脏读,lz还需要基于性能作考虑。

#3


把update包在显式事务中:
begin tran 
update
commit/rollback
这样基本上就没问题了,不过会有点阻塞

#4


谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现

#5


就算是用到事务,但这个操作是没报错的,他会回滚吗,他们只是数据乱了,第二个里面的部份数据被第一个取带了,但实际传进去的是正常的值,在高并发的情况下,数据就乱了

#6


引用 4 楼 wrcyl1314 的回复:
谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。

#7


引用 5 楼 wrcyl1314 的回复:
就算是用到事务,但这个操作是没报错的,他会回滚吗,他们只是数据乱了,第二个里面的部份数据被第一个取带了,但实际传进去的是正常的值,在高并发的情况下,数据就乱了
没错的话不会回滚,你这个应该算是update lost的范畴。加了事务,别的事务就要等待你update完才能用,除非用了with nolock等方式在update过程中读取

#8


我觉得这个应该是由于,你传入的参数导致的问题。

因为不管你是每条几千个update语句,还是只有几个update,sql server都是一样来处理的。

#9


引用 5 楼 wrcyl1314 的回复:
就算是用到事务,但这个操作是没报错的,他会回滚吗,他们只是数据乱了,第二个里面的部份数据被第一个取带了,但实际传进去的是正常的值,在高并发的情况下,数据就乱了


我觉得最有可能出错的,应该就是传入的值,虽然这个看上去是最不容易出错的。

因为sql server的事务,肯定能保证,你的update操作后,数据是一致的,不可能出现,像你这种感觉像开了叉,跑偏了的数据。

#10


引用 6 楼 OrchidCat 的回复:
Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢

#11


引用 10 楼 wrcyl1314 的回复:
Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

#12


高并发的话,会产生阻塞的。这个依靠的因素比较多。但通常会产生阻塞。

参数化实际上就是拼接。(但从方式上说)
数据引擎执行,都是序列化的(在事务的基础上),都是锁定释放锁定... 这样的过程。
同样的参数,在执行上也是这个过程,只是过程很短。

参考。

#13


这个问题可以通过sql profiler来监控,但是考虑到你的事务量非常大,这样的监控肯定是不行的,会把服务器搞的歇菜。


能不能这样,来跟踪一下,update之前的值和之后的值,来进行对比,找到问题:
--记录update之前的值,和之后的值
create table temp_update(
old_id int,old_name varchar(20),old_tel varchar(30),
new_id int,new_name varchar(20),new_tel varchar(30),
)


update table set  name=@name,tel=@tel 
output deleted.id,   --旧的值   
       deleted.name,
       deleted.tel,  
         
       inserted.vid,  --新的记录   
       inserted.name,
       inserted.tel
       
       into temp_update  
where id=@id

#14


引用 11 楼 DBA_Huangzj 的回复:
Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2

#15


你这样传值的确容易出错,或者你可以考虑先保证update的速度前提下,把你的参数转成一个表,然后循环遍历,每次循环只取一个ID,update成功后再改其他。

#16


你这样 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2传的话,很有可能是同时更新(假设更新成功),如果两者之间存在一些依赖关系,数据出错就会出现

#17


引用 14 楼 wrcyl1314 的回复:
Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

#18


引用 16 楼 DBA_Huangzj 的回复:
你这样 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2传的话,很有可能是同时更新(假设更新成功),如果两者之间存在一些依赖关系,数据出错就会出现

谢谢版主回复!
这个是更新同一个表,他们之间没有半点关系,完全独立的两条数据,只是他们在一个表上,如果同时更新的话应该也不会出错才对,因为他们的条件是各自的,都是根据条件来更新
在这种情况下同时更新数据会出错吗?

#19


引用 17 楼 yupeigu 的回复:
Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢

#20


你这个要改还不好改,或者你评估一下这种方法:
把你需要更行的存到一个表,比如你上面的那两个ID,预先处理存入:
tb
name tel id
1 1 1
a b 2

然后update的时候关联这个表来强制对应

#21


引用 20 楼 DBA_Huangzj 的回复:
你这个要改还不好改,或者你评估一下这种方法:
把你需要更行的存到一个表,比如你上面的那两个ID,预先处理存入:
tb
name tel id
1 1 1
a b 2

然后update的时候关联这个表来强制对应

这一定要弄成这么复杂吗,我觉得我的这个问题应该很多大型网站都会碰到,如果他们用了参数化操作的话(如果是拼按SQL字符串不带参数的那种应该没问题)比如更新一个商品的信息,如果是一个很大型的网站写入量很高,那就有很多人同时更新一个表在一个时间点上,那是不是也会出现这样的问题,如果是这样我们是不是直接用SQL拼按,不用参数化操作比较好,只要再去想办法解决SQL的注入问题就行了.
不知道各位大侠,在平时的项目中是怎么操作的呢

#22


引用 19 楼 wrcyl1314 的回复:
Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

#23


引用 22 楼 yupeigu 的回复:
Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法

#24


引用 23 楼 wrcyl1314 的回复:
Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

#25


引用 24 楼 yupeigu 的回复:
Quote: 引用 23 楼 wrcyl1314 的回复:

Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

不是的,他就是一条SQL
private const string editproc = "update SMSSendLog set [addTime]=@SMSSendLog_addTime,[content]=@SMSSendLog_content,[type]=@SMSSendLog_type,[phonelist]=@SMSSendLog_phonelist,[state]=@SMSSendLog_state,[backcode]=@SMSSendLog_backcode where id=@SMSSendLog_id ";
就和这条差不多

#26


引用 25 楼 wrcyl1314 的回复:
Quote: 引用 24 楼 yupeigu 的回复:

Quote: 引用 23 楼 wrcyl1314 的回复:

Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

不是的,他就是一条SQL
private const string editproc = "update SMSSendLog set [addTime]=@SMSSendLog_addTime,[content]=@SMSSendLog_content,[type]=@SMSSendLog_type,[phonelist]=@SMSSendLog_phonelist,[state]=@SMSSendLog_state,[backcode]=@SMSSendLog_backcode where id=@SMSSendLog_id ";
就和这条差不多


哦,然后,参数是通过刚才的c#代码,来传入的是吗?

#27


引用 26 楼 yupeigu 的回复:
Quote: 引用 25 楼 wrcyl1314 的回复:

Quote: 引用 24 楼 yupeigu 的回复:

Quote: 引用 23 楼 wrcyl1314 的回复:

Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

不是的,他就是一条SQL
private const string editproc = "update SMSSendLog set [addTime]=@SMSSendLog_addTime,[content]=@SMSSendLog_content,[type]=@SMSSendLog_type,[phonelist]=@SMSSendLog_phonelist,[state]=@SMSSendLog_state,[backcode]=@SMSSendLog_backcode where id=@SMSSendLog_id ";
就和这条差不多


哦,然后,参数是通过刚才的c#代码,来传入的是吗?

是的,执行语句就一条,然后每次操作都会调用一次传入方法,每次传进去都是一组,因为每个用户是独立的所以传入之前信息是不存在共享或是跑偏的,主要是传进去以后会发生什么事就不知道了

#28


小弟觉得该跟踪C#代码,看看每一步的参数值

#29


引用 28 楼 chen357313771 的回复:
小弟觉得该跟踪C#代码,看看每一步的参数值

首先程序上应该是没问题,因为程序一出问题会一直出问题,不会偶尔也问题
然后就是这个是多用户同时访问时的并发,不是一个人的调试跟踪代码应该是行不通的,如果让它一点一点执行肯定是不会出问题的
最后就是每次调用的方法,传进去的值都是死的
比如:
UpStar('1','2',1);
UpStar('a','b',2);
在这种情况下应该不会出现C#程序问题吧
但在并发数很高的情况下,会得到  '1','2',2  这种结果

#30


他瞎折腾。使用了多线程。对于这种update操作,不要使用dotnet的多线程

#31


肯定是楼主的代码有问题了,每秒几千次更新,怎么确保没有传错参数呢?

#32


引用 29 楼 wrcyl1314 的回复:
Quote: 引用 28 楼 chen357313771 的回复:

小弟觉得该跟踪C#代码,看看每一步的参数值

首先程序上应该是没问题,因为程序一出问题会一直出问题,不会偶尔也问题
然后就是这个是多用户同时访问时的并发,不是一个人的调试跟踪代码应该是行不通的,如果让它一点一点执行肯定是不会出问题的
最后就是每次调用的方法,传进去的值都是死的
比如:
UpStar('1','2',1);
UpStar('a','b',2);
在这种情况下应该不会出现C#程序问题吧
但在并发数很高的情况下,会得到  '1','2',2  这种结果

觉得这应该考虑考虑线程安全方面,因为像这种高并发的都是访问的缓存,数据库的信息放在缓存里的。
只有最后提交的时候是操作数据库的。多线程操作数据库一般应该是这样的,前面多线程处理数据后,把数据放到一个队列,不管是程序自带的list还是字典什么的,然后由另外的专门处理数据的线程从这里取走数据,然后入库或者更新数据库。。。
小弟不才,也是请教前辈告诉我的一些分析,我也学习了,呵呵。
发生这现象的问题很大程度应该是你的代码了,检查一下吧,比如加锁的地方什么的。。嘿

#33


引用 32 楼 chen357313771 的回复:
Quote: 引用 29 楼 wrcyl1314 的回复:

Quote: 引用 28 楼 chen357313771 的回复:

小弟觉得该跟踪C#代码,看看每一步的参数值

首先程序上应该是没问题,因为程序一出问题会一直出问题,不会偶尔也问题
然后就是这个是多用户同时访问时的并发,不是一个人的调试跟踪代码应该是行不通的,如果让它一点一点执行肯定是不会出问题的
最后就是每次调用的方法,传进去的值都是死的
比如:
UpStar('1','2',1);
UpStar('a','b',2);
在这种情况下应该不会出现C#程序问题吧
但在并发数很高的情况下,会得到  '1','2',2  这种结果

觉得这应该考虑考虑线程安全方面,因为像这种高并发的都是访问的缓存,数据库的信息放在缓存里的。
只有最后提交的时候是操作数据库的。多线程操作数据库一般应该是这样的,前面多线程处理数据后,把数据放到一个队列,不管是程序自带的list还是字典什么的,然后由另外的专门处理数据的线程从这里取走数据,然后入库或者更新数据库。。。
小弟不才,也是请教前辈告诉我的一些分析,我也学习了,呵呵。
发生这现象的问题很大程度应该是你的代码了,检查一下吧,比如加锁的地方什么的。。嘿

多线程中加锁,不能加大范围,不能加耗时操作,这些都要注意。
比如一个业务接口,一堆的逻辑,然后最后一步是写数据库,那这个锁就只加到写数据库这步,而不是把整个方法加锁等

#34


个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

#35


引用 34 楼 wufeng4552 的回复:
个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

首先谢谢各位的回复和帮助!
在程序里面每次调用之后,参数都被清空了,然后下一次重新给的值,按各位的分析的话,现在问题不是出在SQL就出在ADO.NET里面
我现在不是在做测试,而是实际上碰到了这个问题,一个投票系统,有人用刷票软件一直的刷,因为种种原因设计成在程序上把数据累加以后再写入数据库(这样做的原因不必深究,现在只是要找到这种问题的源头)
现在出现的情况就是当有人投另一个一票时,这个票数突然之间变成了那个刷票的人的
也就说现在
A 有100票,然后他用刷票软件1秒钟刷几千票,1分钟后他有10000票了,
B 有点10票, 然后在上一人一直在刷票的同时有人投了B一票,在投票成功的这一瞬间B的票数就变成和A一样了,他就直接从10变成了10000票
投票的程序执行过程是这样的
取出一个人的票数和ID 然后把票数+1再把数据存进去(请各位不要计较为什么这么做)
所以情况就和我上面说的一样,都是根据ID来更新,结果他们的票数乱了,B得到了A的票数,他们都是在自己的电脑上操作,提交给服务器,在服务器上确实是多线程并发操作.

#36


引用 35 楼 wrcyl1314 的回复:
Quote: 引用 34 楼 wufeng4552 的回复:

个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

首先谢谢各位的回复和帮助!
在程序里面每次调用之后,参数都被清空了,然后下一次重新给的值,按各位的分析的话,现在问题不是出在SQL就出在ADO.NET里面
我现在不是在做测试,而是实际上碰到了这个问题,一个投票系统,有人用刷票软件一直的刷,因为种种原因设计成在程序上把数据累加以后再写入数据库(这样做的原因不必深究,现在只是要找到这种问题的源头)
现在出现的情况就是当有人投另一个一票时,这个票数突然之间变成了那个刷票的人的
也就说现在
A 有100票,然后他用刷票软件1秒钟刷几千票,1分钟后他有10000票了,
B 有点10票, 然后在上一人一直在刷票的同时有人投了B一票,在投票成功的这一瞬间B的票数就变成和A一样了,他就直接从10变成了10000票
投票的程序执行过程是这样的
取出一个人的票数和ID 然后把票数+1再把数据存进去(请各位不要计较为什么这么做)
所以情况就和我上面说的一样,都是根据ID来更新,结果他们的票数乱了,B得到了A的票数,他们都是在自己的电脑上操作,提交给服务器,在服务器上确实是多线程并发操作.


从逻辑上看,似乎没什么问题,先把票数+1,然后再把数据存进去。

但是,对sql server来说,只要你给的参数时xx,那么他就按照xx来查询,然后update里面数据,应该是不会错的,当然,你的事务量非常大,但应该也不会出错。

应该是传入的参数,再累积的时候,而且又是并发线程,可能哪儿出现了问题。

能不能这样,如果你们有测试系统,你在测试系统上模拟这种,有问题的情况,看能不能重新这种错误,也就是猜测了,然后去验证。否则,这样光猜测也不行,也不行。

#37


请说下你的数据库版本,建议你升级到最新版,有点像广告,呵呵,感觉就是这个问题。

#38


引用 36 楼 yupeigu 的回复:
Quote: 引用 35 楼 wrcyl1314 的回复:

Quote: 引用 34 楼 wufeng4552 的回复:

个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

首先谢谢各位的回复和帮助!
在程序里面每次调用之后,参数都被清空了,然后下一次重新给的值,按各位的分析的话,现在问题不是出在SQL就出在ADO.NET里面
我现在不是在做测试,而是实际上碰到了这个问题,一个投票系统,有人用刷票软件一直的刷,因为种种原因设计成在程序上把数据累加以后再写入数据库(这样做的原因不必深究,现在只是要找到这种问题的源头)
现在出现的情况就是当有人投另一个一票时,这个票数突然之间变成了那个刷票的人的
也就说现在
A 有100票,然后他用刷票软件1秒钟刷几千票,1分钟后他有10000票了,
B 有点10票, 然后在上一人一直在刷票的同时有人投了B一票,在投票成功的这一瞬间B的票数就变成和A一样了,他就直接从10变成了10000票
投票的程序执行过程是这样的
取出一个人的票数和ID 然后把票数+1再把数据存进去(请各位不要计较为什么这么做)
所以情况就和我上面说的一样,都是根据ID来更新,结果他们的票数乱了,B得到了A的票数,他们都是在自己的电脑上操作,提交给服务器,在服务器上确实是多线程并发操作.


从逻辑上看,似乎没什么问题,先把票数+1,然后再把数据存进去。

但是,对sql server来说,只要你给的参数时xx,那么他就按照xx来查询,然后update里面数据,应该是不会错的,当然,你的事务量非常大,但应该也不会出错。

应该是传入的参数,再累积的时候,而且又是并发线程,可能哪儿出现了问题。

能不能这样,如果你们有测试系统,你在测试系统上模拟这种,有问题的情况,看能不能重新这种错误,也就是猜测了,然后去验证。否则,这样光猜测也不行,也不行。


现在数据库版本是sql 2008R2
看来只能测试摸索一下了,不知道各位有没有碰到过高并发的数据更新问题呢,是怎么设计的呢,是不是所有的操作都放到存储过程用事务处理呢,因为现在程序设计成可以换数据库的,所以没用存储过程直接用的SQL语句,是不是用存储过程就不会出现这种情况呢

#39


你换成ORACLE,再用测试,我估计是数据库的问题。

#40


印象中 ,企业的大数据库,并发数多的,几乎都是ORACLE。你不服老大是不行的。

#41


还没有遇到过

#42


引用 40 楼 qq112141874 的回复:
印象中 ,企业的大数据库,并发数多的,几乎都是ORACLE。你不服老大是不行的。
并发数高时,数据库数据会混乱,好像和参数化查询有关
那就是只能换数据库解析了

#1


你查询的时候用了with nolock?

#2


这个是没用好事务的问题。不是数据库机制的问题。

参数化也好,还是原来的标准语句,都需要良好的事务支持。脏读,幻影啥的,都是要考虑的问题。

并发高,如果允许脏读发生,那基本都没啥性能上的干扰。
如果严格的控制脏读,lz还需要基于性能作考虑。

#3


把update包在显式事务中:
begin tran 
update
commit/rollback
这样基本上就没问题了,不过会有点阻塞

#4


谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现

#5


就算是用到事务,但这个操作是没报错的,他会回滚吗,他们只是数据乱了,第二个里面的部份数据被第一个取带了,但实际传进去的是正常的值,在高并发的情况下,数据就乱了

#6


引用 4 楼 wrcyl1314 的回复:
谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。

#7


引用 5 楼 wrcyl1314 的回复:
就算是用到事务,但这个操作是没报错的,他会回滚吗,他们只是数据乱了,第二个里面的部份数据被第一个取带了,但实际传进去的是正常的值,在高并发的情况下,数据就乱了
没错的话不会回滚,你这个应该算是update lost的范畴。加了事务,别的事务就要等待你update完才能用,除非用了with nolock等方式在update过程中读取

#8


我觉得这个应该是由于,你传入的参数导致的问题。

因为不管你是每条几千个update语句,还是只有几个update,sql server都是一样来处理的。

#9


引用 5 楼 wrcyl1314 的回复:
就算是用到事务,但这个操作是没报错的,他会回滚吗,他们只是数据乱了,第二个里面的部份数据被第一个取带了,但实际传进去的是正常的值,在高并发的情况下,数据就乱了


我觉得最有可能出错的,应该就是传入的值,虽然这个看上去是最不容易出错的。

因为sql server的事务,肯定能保证,你的update操作后,数据是一致的,不可能出现,像你这种感觉像开了叉,跑偏了的数据。

#10


引用 6 楼 OrchidCat 的回复:
Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢

#11


引用 10 楼 wrcyl1314 的回复:
Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

#12


高并发的话,会产生阻塞的。这个依靠的因素比较多。但通常会产生阻塞。

参数化实际上就是拼接。(但从方式上说)
数据引擎执行,都是序列化的(在事务的基础上),都是锁定释放锁定... 这样的过程。
同样的参数,在执行上也是这个过程,只是过程很短。

参考。

#13


这个问题可以通过sql profiler来监控,但是考虑到你的事务量非常大,这样的监控肯定是不行的,会把服务器搞的歇菜。


能不能这样,来跟踪一下,update之前的值和之后的值,来进行对比,找到问题:
--记录update之前的值,和之后的值
create table temp_update(
old_id int,old_name varchar(20),old_tel varchar(30),
new_id int,new_name varchar(20),new_tel varchar(30),
)


update table set  name=@name,tel=@tel 
output deleted.id,   --旧的值   
       deleted.name,
       deleted.tel,  
         
       inserted.vid,  --新的记录   
       inserted.name,
       inserted.tel
       
       into temp_update  
where id=@id

#14


引用 11 楼 DBA_Huangzj 的回复:
Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2

#15


你这样传值的确容易出错,或者你可以考虑先保证update的速度前提下,把你的参数转成一个表,然后循环遍历,每次循环只取一个ID,update成功后再改其他。

#16


你这样 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2传的话,很有可能是同时更新(假设更新成功),如果两者之间存在一些依赖关系,数据出错就会出现

#17


引用 14 楼 wrcyl1314 的回复:
Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

#18


引用 16 楼 DBA_Huangzj 的回复:
你这样 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2传的话,很有可能是同时更新(假设更新成功),如果两者之间存在一些依赖关系,数据出错就会出现

谢谢版主回复!
这个是更新同一个表,他们之间没有半点关系,完全独立的两条数据,只是他们在一个表上,如果同时更新的话应该也不会出错才对,因为他们的条件是各自的,都是根据条件来更新
在这种情况下同时更新数据会出错吗?

#19


引用 17 楼 yupeigu 的回复:
Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢

#20


你这个要改还不好改,或者你评估一下这种方法:
把你需要更行的存到一个表,比如你上面的那两个ID,预先处理存入:
tb
name tel id
1 1 1
a b 2

然后update的时候关联这个表来强制对应

#21


引用 20 楼 DBA_Huangzj 的回复:
你这个要改还不好改,或者你评估一下这种方法:
把你需要更行的存到一个表,比如你上面的那两个ID,预先处理存入:
tb
name tel id
1 1 1
a b 2

然后update的时候关联这个表来强制对应

这一定要弄成这么复杂吗,我觉得我的这个问题应该很多大型网站都会碰到,如果他们用了参数化操作的话(如果是拼按SQL字符串不带参数的那种应该没问题)比如更新一个商品的信息,如果是一个很大型的网站写入量很高,那就有很多人同时更新一个表在一个时间点上,那是不是也会出现这样的问题,如果是这样我们是不是直接用SQL拼按,不用参数化操作比较好,只要再去想办法解决SQL的注入问题就行了.
不知道各位大侠,在平时的项目中是怎么操作的呢

#22


引用 19 楼 wrcyl1314 的回复:
Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

#23


引用 22 楼 yupeigu 的回复:
Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法

#24


引用 23 楼 wrcyl1314 的回复:
Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

#25


引用 24 楼 yupeigu 的回复:
Quote: 引用 23 楼 wrcyl1314 的回复:

Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

不是的,他就是一条SQL
private const string editproc = "update SMSSendLog set [addTime]=@SMSSendLog_addTime,[content]=@SMSSendLog_content,[type]=@SMSSendLog_type,[phonelist]=@SMSSendLog_phonelist,[state]=@SMSSendLog_state,[backcode]=@SMSSendLog_backcode where id=@SMSSendLog_id ";
就和这条差不多

#26


引用 25 楼 wrcyl1314 的回复:
Quote: 引用 24 楼 yupeigu 的回复:

Quote: 引用 23 楼 wrcyl1314 的回复:

Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

不是的,他就是一条SQL
private const string editproc = "update SMSSendLog set [addTime]=@SMSSendLog_addTime,[content]=@SMSSendLog_content,[type]=@SMSSendLog_type,[phonelist]=@SMSSendLog_phonelist,[state]=@SMSSendLog_state,[backcode]=@SMSSendLog_backcode where id=@SMSSendLog_id ";
就和这条差不多


哦,然后,参数是通过刚才的c#代码,来传入的是吗?

#27


引用 26 楼 yupeigu 的回复:
Quote: 引用 25 楼 wrcyl1314 的回复:

Quote: 引用 24 楼 yupeigu 的回复:

Quote: 引用 23 楼 wrcyl1314 的回复:

Quote: 引用 22 楼 yupeigu 的回复:

Quote: 引用 19 楼 wrcyl1314 的回复:

Quote: 引用 17 楼 yupeigu 的回复:

Quote: 引用 14 楼 wrcyl1314 的回复:

Quote: 引用 11 楼 DBA_Huangzj 的回复:

Quote: 引用 10 楼 wrcyl1314 的回复:

Quote: 引用 6 楼 OrchidCat 的回复:

Quote: 引用 4 楼 wrcyl1314 的回复:

谢谢两位的即时回答,不过现在问题不是脏读的问题,现在没有读操作只有写操作
因为现在这两条数据是完全独立的,是根据ID来区分的
也就是说一个操作是只修改ID=1的值,另一个操作是修改ID=2的值,结果是当有一个的修改频率很高时,他的值就干犹到了第二个数据,当然也不是一直出现,只是会偶尔出现


这个其实是说的第一个问题,事务隔离性,像3楼老黄写的那样,做好事务,应该不会出现这个问题。
另外,不排除where语句拼接产生的错误.lz这块,可能需要进行一下排查。


谢谢回复,如果这些操作都用事务会不会出现阻塞就像3楼说的,还有就是我这条语句是不存在where语句拼接的,就只有一条语句,中间的参数用参数化传值,其实我更想知道为什么会出现这种情况,这种参数化传值的内部原理是什么呢,它们是否存在隔离呢,就是两个相同的操作,参数是一样的,他们会不会相互影响呢
阻塞需要考虑代码和索引是否合理,正常来说不会阻塞很久,如果你大面积UPDATE,那么肯定阻塞很久。参数化的其中一个不好处就是可能出现参数嗅探,导致产生不高效的执行计划,影响查询

现在就是大面积的UPDATE所以不敢用事务,而且我现在最想要解决的问题是为什么它会出现这种情况,也许用事务它就好了,隔离了,但我心里面的那个问题还是没解决,
update table set  name='1',tel='2' where id=1 这样肯定没问题,但改成
update table set  name=@name,tel=@tel where id=@id就乱了
而且参数都是一组一组传进去的,不可能只改变其中的一些量
比如说我传值时  @name='1' @tel='2' @id=1  这就是一组,就算改错那也只是ID=1的数据错
但现在出现的情况是传入 @name='1' @tel='2' @id=1,@name='a' @tel='b' @id=2得到的结果是
id  name   tel
 1    1     2
 2    1     2
因为数据都正常的更新上去了,只是跑偏了,给我的感觉就是在执行时参数乱了,本来是第一组的参数跑到了第二组,好像参数之间没有隔离
如果真的是这种情况的话,就算你用行锁应该都不行吧,因为在这条SQL真正产生时就己经是错误的了
可能在一个点上产生了一条这样的SQL   update table set  name='1',tel='2' where id=2


嗯,对就是这种错误,导致的,真是跑偏了,现在的问题是你有什么办法,先把错误的数据改过来。

然后,检查一下你的代码,是否还有一些没考虑到的问题,再改改。

您的意思是我猜对了?那就是说参数化操作时在高并发下确实会混乱,他们之间没有完全的隔离,那是不是数据库的机制问题呢


哦 不是,参数化操作,照理应该不会引起你的问题,应该是在不断的运行语句时,由于你传入的参数有问题,导致了某些数据,出错了,而这些出错的原因,在于传入的参数跑偏了。

现在的关键是,我们得查出,为什么传入的参数,会出现这种跑偏的情况,这个@id,@name,@tel,是怎么出传进去的,这些传进去的值,又是从何处生成的

是用程序传参数进去,.net 的程序
if (conn.State != ConnectionState.Open)
                conn.Open(); 
            cmd.Connection = conn;
            cmd.CommandText = cmdText; 
            if (trans != null)
                cmd.Transaction = trans; 
            cmd.CommandType = cmdType; 
            if (cmdParms != null)
            {
                cmd.Parameters.AddRange(cmdParms);
                cmdParms = null;
                 
            }

写入参数的代码大致是这样的,有个方法调用他,每一次的操作,就是调用一次这个方法


对了 这个有问题的update语句,应该也是在一个存储过程中的吧。

不是的,他就是一条SQL
private const string editproc = "update SMSSendLog set [addTime]=@SMSSendLog_addTime,[content]=@SMSSendLog_content,[type]=@SMSSendLog_type,[phonelist]=@SMSSendLog_phonelist,[state]=@SMSSendLog_state,[backcode]=@SMSSendLog_backcode where id=@SMSSendLog_id ";
就和这条差不多


哦,然后,参数是通过刚才的c#代码,来传入的是吗?

是的,执行语句就一条,然后每次操作都会调用一次传入方法,每次传进去都是一组,因为每个用户是独立的所以传入之前信息是不存在共享或是跑偏的,主要是传进去以后会发生什么事就不知道了

#28


小弟觉得该跟踪C#代码,看看每一步的参数值

#29


引用 28 楼 chen357313771 的回复:
小弟觉得该跟踪C#代码,看看每一步的参数值

首先程序上应该是没问题,因为程序一出问题会一直出问题,不会偶尔也问题
然后就是这个是多用户同时访问时的并发,不是一个人的调试跟踪代码应该是行不通的,如果让它一点一点执行肯定是不会出问题的
最后就是每次调用的方法,传进去的值都是死的
比如:
UpStar('1','2',1);
UpStar('a','b',2);
在这种情况下应该不会出现C#程序问题吧
但在并发数很高的情况下,会得到  '1','2',2  这种结果

#30


他瞎折腾。使用了多线程。对于这种update操作,不要使用dotnet的多线程

#31


肯定是楼主的代码有问题了,每秒几千次更新,怎么确保没有传错参数呢?

#32


引用 29 楼 wrcyl1314 的回复:
Quote: 引用 28 楼 chen357313771 的回复:

小弟觉得该跟踪C#代码,看看每一步的参数值

首先程序上应该是没问题,因为程序一出问题会一直出问题,不会偶尔也问题
然后就是这个是多用户同时访问时的并发,不是一个人的调试跟踪代码应该是行不通的,如果让它一点一点执行肯定是不会出问题的
最后就是每次调用的方法,传进去的值都是死的
比如:
UpStar('1','2',1);
UpStar('a','b',2);
在这种情况下应该不会出现C#程序问题吧
但在并发数很高的情况下,会得到  '1','2',2  这种结果

觉得这应该考虑考虑线程安全方面,因为像这种高并发的都是访问的缓存,数据库的信息放在缓存里的。
只有最后提交的时候是操作数据库的。多线程操作数据库一般应该是这样的,前面多线程处理数据后,把数据放到一个队列,不管是程序自带的list还是字典什么的,然后由另外的专门处理数据的线程从这里取走数据,然后入库或者更新数据库。。。
小弟不才,也是请教前辈告诉我的一些分析,我也学习了,呵呵。
发生这现象的问题很大程度应该是你的代码了,检查一下吧,比如加锁的地方什么的。。嘿

#33


引用 32 楼 chen357313771 的回复:
Quote: 引用 29 楼 wrcyl1314 的回复:

Quote: 引用 28 楼 chen357313771 的回复:

小弟觉得该跟踪C#代码,看看每一步的参数值

首先程序上应该是没问题,因为程序一出问题会一直出问题,不会偶尔也问题
然后就是这个是多用户同时访问时的并发,不是一个人的调试跟踪代码应该是行不通的,如果让它一点一点执行肯定是不会出问题的
最后就是每次调用的方法,传进去的值都是死的
比如:
UpStar('1','2',1);
UpStar('a','b',2);
在这种情况下应该不会出现C#程序问题吧
但在并发数很高的情况下,会得到  '1','2',2  这种结果

觉得这应该考虑考虑线程安全方面,因为像这种高并发的都是访问的缓存,数据库的信息放在缓存里的。
只有最后提交的时候是操作数据库的。多线程操作数据库一般应该是这样的,前面多线程处理数据后,把数据放到一个队列,不管是程序自带的list还是字典什么的,然后由另外的专门处理数据的线程从这里取走数据,然后入库或者更新数据库。。。
小弟不才,也是请教前辈告诉我的一些分析,我也学习了,呵呵。
发生这现象的问题很大程度应该是你的代码了,检查一下吧,比如加锁的地方什么的。。嘿

多线程中加锁,不能加大范围,不能加耗时操作,这些都要注意。
比如一个业务接口,一堆的逻辑,然后最后一步是写数据库,那这个锁就只加到写数据库这步,而不是把整个方法加锁等

#34


个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

#35


引用 34 楼 wufeng4552 的回复:
个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

首先谢谢各位的回复和帮助!
在程序里面每次调用之后,参数都被清空了,然后下一次重新给的值,按各位的分析的话,现在问题不是出在SQL就出在ADO.NET里面
我现在不是在做测试,而是实际上碰到了这个问题,一个投票系统,有人用刷票软件一直的刷,因为种种原因设计成在程序上把数据累加以后再写入数据库(这样做的原因不必深究,现在只是要找到这种问题的源头)
现在出现的情况就是当有人投另一个一票时,这个票数突然之间变成了那个刷票的人的
也就说现在
A 有100票,然后他用刷票软件1秒钟刷几千票,1分钟后他有10000票了,
B 有点10票, 然后在上一人一直在刷票的同时有人投了B一票,在投票成功的这一瞬间B的票数就变成和A一样了,他就直接从10变成了10000票
投票的程序执行过程是这样的
取出一个人的票数和ID 然后把票数+1再把数据存进去(请各位不要计较为什么这么做)
所以情况就和我上面说的一样,都是根据ID来更新,结果他们的票数乱了,B得到了A的票数,他们都是在自己的电脑上操作,提交给服务器,在服务器上确实是多线程并发操作.

#36


引用 35 楼 wrcyl1314 的回复:
Quote: 引用 34 楼 wufeng4552 的回复:

个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

首先谢谢各位的回复和帮助!
在程序里面每次调用之后,参数都被清空了,然后下一次重新给的值,按各位的分析的话,现在问题不是出在SQL就出在ADO.NET里面
我现在不是在做测试,而是实际上碰到了这个问题,一个投票系统,有人用刷票软件一直的刷,因为种种原因设计成在程序上把数据累加以后再写入数据库(这样做的原因不必深究,现在只是要找到这种问题的源头)
现在出现的情况就是当有人投另一个一票时,这个票数突然之间变成了那个刷票的人的
也就说现在
A 有100票,然后他用刷票软件1秒钟刷几千票,1分钟后他有10000票了,
B 有点10票, 然后在上一人一直在刷票的同时有人投了B一票,在投票成功的这一瞬间B的票数就变成和A一样了,他就直接从10变成了10000票
投票的程序执行过程是这样的
取出一个人的票数和ID 然后把票数+1再把数据存进去(请各位不要计较为什么这么做)
所以情况就和我上面说的一样,都是根据ID来更新,结果他们的票数乱了,B得到了A的票数,他们都是在自己的电脑上操作,提交给服务器,在服务器上确实是多线程并发操作.


从逻辑上看,似乎没什么问题,先把票数+1,然后再把数据存进去。

但是,对sql server来说,只要你给的参数时xx,那么他就按照xx来查询,然后update里面数据,应该是不会错的,当然,你的事务量非常大,但应该也不会出错。

应该是传入的参数,再累积的时候,而且又是并发线程,可能哪儿出现了问题。

能不能这样,如果你们有测试系统,你在测试系统上模拟这种,有问题的情况,看能不能重新这种错误,也就是猜测了,然后去验证。否则,这样光猜测也不行,也不行。

#37


请说下你的数据库版本,建议你升级到最新版,有点像广告,呵呵,感觉就是这个问题。

#38


引用 36 楼 yupeigu 的回复:
Quote: 引用 35 楼 wrcyl1314 的回复:

Quote: 引用 34 楼 wufeng4552 的回复:

个人觉得不是高并发情况下sp导致参数跑偏
而是在传入之前就已经偏了
有可能是程序导致
尝试下在每次调用过程之前将参数之前的值清空

首先谢谢各位的回复和帮助!
在程序里面每次调用之后,参数都被清空了,然后下一次重新给的值,按各位的分析的话,现在问题不是出在SQL就出在ADO.NET里面
我现在不是在做测试,而是实际上碰到了这个问题,一个投票系统,有人用刷票软件一直的刷,因为种种原因设计成在程序上把数据累加以后再写入数据库(这样做的原因不必深究,现在只是要找到这种问题的源头)
现在出现的情况就是当有人投另一个一票时,这个票数突然之间变成了那个刷票的人的
也就说现在
A 有100票,然后他用刷票软件1秒钟刷几千票,1分钟后他有10000票了,
B 有点10票, 然后在上一人一直在刷票的同时有人投了B一票,在投票成功的这一瞬间B的票数就变成和A一样了,他就直接从10变成了10000票
投票的程序执行过程是这样的
取出一个人的票数和ID 然后把票数+1再把数据存进去(请各位不要计较为什么这么做)
所以情况就和我上面说的一样,都是根据ID来更新,结果他们的票数乱了,B得到了A的票数,他们都是在自己的电脑上操作,提交给服务器,在服务器上确实是多线程并发操作.


从逻辑上看,似乎没什么问题,先把票数+1,然后再把数据存进去。

但是,对sql server来说,只要你给的参数时xx,那么他就按照xx来查询,然后update里面数据,应该是不会错的,当然,你的事务量非常大,但应该也不会出错。

应该是传入的参数,再累积的时候,而且又是并发线程,可能哪儿出现了问题。

能不能这样,如果你们有测试系统,你在测试系统上模拟这种,有问题的情况,看能不能重新这种错误,也就是猜测了,然后去验证。否则,这样光猜测也不行,也不行。


现在数据库版本是sql 2008R2
看来只能测试摸索一下了,不知道各位有没有碰到过高并发的数据更新问题呢,是怎么设计的呢,是不是所有的操作都放到存储过程用事务处理呢,因为现在程序设计成可以换数据库的,所以没用存储过程直接用的SQL语句,是不是用存储过程就不会出现这种情况呢

#39


你换成ORACLE,再用测试,我估计是数据库的问题。

#40


印象中 ,企业的大数据库,并发数多的,几乎都是ORACLE。你不服老大是不行的。

#41


还没有遇到过

#42


引用 40 楼 qq112141874 的回复:
印象中 ,企业的大数据库,并发数多的,几乎都是ORACLE。你不服老大是不行的。
并发数高时,数据库数据会混乱,好像和参数化查询有关
那就是只能换数据库解析了