识别哪些记录“等待同步”的逻辑当然是基于ROWVERSION值,包括使用MIN_ACTIVE_ROWVERSION()来避免脏读.
所有SELECT操作都封装在每个“源”端的SP中.这是一个SP的示意样本:
PROCEDURE LoaderRetrieve(@LastStamp bigint,@Rows int) BEGIN ... (vars handling) ... SET TRANSACTION ISOLATION LEVEL SNAPSHOT Select TOP (@Rows) Field1,Field2,Field3 FROM Table WHERE [RowVersion] > @LastStampAsRowVersionDataType AND [RowVersion] < @MinActiveVersion Order by [RowVersion] END
该方法工作正常,我们通常以600k /小时的预期速率(每30秒作业,批量大小= 5k)同步记录,但是在某些时候,同步过程没有找到要传输的单个记录,即使有数千个ROWVERSION值大于@LastStamp参数的记录.
当检查原因时,我们发现MIN_ACTIVE_ROWVERSION()的值正在被搜索的@LastStamp值小于(或稍大于5或10增量).这当然不应该是一个问题,因为引入了MIN_ACTIVE_ROWVERSION()方法以避免脏读和后期问题,但是:
在上述情况发生的情况下,我们在某些情况下看到的问题是,MIN_ACTIVE_ROWVERSION()的值在长(很长)的时间段内不会改变,例如30/40分钟,有时超过一小时.这个值远远小于@@ DBTS值.
我们首先认为这与尚未提交的待处理数据库事务有关.根据MSDN关于MIN_ACTIVE_ROWVERSION()(link)的定义:
Returns the lowest active rowversion value in the current database. A rowversion value is active if it is used in a transaction that has not yet been committed.
但是当使用open_tran>检查会话(sys.sysprocesses)时在这个问题的持续时间内,我们找不到任何等待时间超过几秒的会话,只有一到两次/ 5分钟的等待时间会话.
所以在这一点上,我们正在努力去理解这种情况:MIN_ACTIVE_ROWVERSION()在很长一段时间内没有改变,在这段时间内没有找到长时间等待的未提交的事务.
我不是DBA,可能是我们在图片中缺少一些东西来分析这个问题,在论坛和博客上进行一些研究找不到任何其他线索.到目前为止,open_tran> 0是有效的理由,但在我暴露的情况下,很明显有其他的东西,不知道为什么.
任何反馈都不胜感激.
解决方法
问题是我们正在寻找一个漫长的等待时间的会话,但真正的交易是找到一段时间以来有活动的会话.
如果有一个会话,其中open_tran = 1,从这个事务打开(当然仍然是活动,尚未提交)开始就准确地获得,那么应该检查sys.sysprocesses中的last_batch字段.
使用此查询:
select batchDurationMin= DATEDIFF(second,last_batch,getutcdate())/60.0,batchDurationSecs= DATEDIFF(second,getutcdate()),hostname,open_tran,* from sys.sysprocesses a where spid > 50 and a.open_tran >0 order by last_batch asc
我们可以识别一个开放的活动的活动30分钟.并且通过主机名值和一些更多的Web服务检查(以及使用dbcc inputbuffer),我们发现了负责的过程.
所以,最后一个问题实际上是“确实有一个未提交事务的活动会话”,因此MIN_ACTIVE_ROWVERSION()不会改变.我们只是看错了标准的进程.
现在我们知道哪个进程的行为是这样的,下一步将是改进它.
希望这个结果对别人有用.