SQL Server版本列的更新速度超出预期

时间:2009-12-06 12:10:04

标签: sql-server nhibernate

我们正在使用NHibernate更新用户余额的帐户表。阻碍我们的一个测试案例是:


var s = NHibernateHelper.OpenSession();
var q = s.CreateQuery("Update Account set Balance=? where UserId=? and Version=?");
var acc = s.Load(1);
ITransaction tx = null;
for (int j = 0; j < NUM_UPDATES; j++)
{
    int rowcount = 0;
    var tx = s.BeginTransaction();
    do
    {
        s.Refresh(acc);
        q.SetDouble(0, acc.Balance + _amount).SetInt32(1, 1).SetBinary(2, acc.Version);
        rowcount = q.ExecuteUpdate();
    } while (rowcount <= 0);
    tx.Commit();
}

此代码同时在单个线程和多个线程中执行(因此版本控制)。它正确执行,但是 - 版本号增加了一个数字,该数字比实际更新计数(NUM_UPDATES)增加了一些值。

e.g。如果我们进行16次更新,版本号将增加16或17.如果我们进行1000次更新,版本号将增加1004。

如果16个线程运行相同的代码(在4核机器上),每个代码有1000个更新,那么我们显然会进行大量重试,并且版本增加16064(1004 * 16)。

知道是什么导致了这个吗?是否有引起警报的原因?

3 个答案:

答案 0 :(得分:4)

如果版本列的类型为timestamp或rowversion,则使用全局计数器更新它。只要插入或更新包含rowversion列的任何表中的任何行,该全局计数器就会递增。 因此,这不是一个值得关注的问题。它仅反映数据库中的其他活动。

答案 1 :(得分:0)

Read here 有关SQL Server中rowvwersion (timestamp)的更多信息。要了解的事情:

  • 与时间无关;除了后面生成的更大的数字。
  • 该计数器是数据库全局的。
  • 它是自动更改的,您不需要更改它。
  • 可用于查询以检测数据更改,同步期间等。

答案 2 :(得分:0)

由于您正在构建自己的查询,因此可以在UPDATE中以原子方式递增列:

UPDATE Account SET Balance = Balance + @amount WHERE UserId = @uid

这也将节省创建和提交单独事务的开销。