web-dev-qa-db-ja.com

SQL Server RowVersion / Timestamp-比較

RowVersion列の値自体は、行が更新されるたびに変更されることを除いて、実際には役に立たないことを知っています。しかし、私はそれらが相対的(不平等)比較に役立つかどうか疑問に思っていました。

RowVersion列を持つテーブルがある場合、次のいずれかが当てはまります。

  • 同時に発生するすべての更新(同じ更新ステートメントまたは同じトランザクション)のRowVersion列の値は同じですか?
  • 「A」を更新してから「B」を更新すると、更新「B」に関係する行の値が更新「A」に関係する行よりも高くなりますか?

ありがとう。

27
David Pfeffer

MSDNから

各データベースには、データベース内のrowversion列を含むテーブルで実行される挿入または更新ごとに増分操作であるカウンターがあります。このカウンターはデータベースrowversionです。これは、クロックに関連付けることができる実際の時間ではなく、データベース内の相対時間を追跡します。 毎回それrowversion変更または挿入増分データベースrowversionvaluerowversion列に挿入されます。

http://msdn.Microsoft.com/en-us/library/ms182776.aspx

  • 私が理解している限り、システムでは実際には同時に何も起こりません。つまり、すべてのrowversionsは一意である必要があります。同じテーブル内で重複が許可されている場合、それらは事実上役に立たないと言ってもいいでしょう。また、複製されないrowversionsに信用を与えることは、違反を引き起こすのではなく、外部キーの問題を引き起こすので、それらを主キーとして使用しないというMSDNのスタンスです。
  • MSDNによると、「rowversionデータ型は単に増加する数値です...」ので、そうです、後で大きいです。

どれだけ増加するかの質問に対して、MSDNは「[rowversion]はデータベース内の相対時間を追跡する」と述べており、流動的な整数ではないことを示しています増加しますが、時間ベースです。ただし、この「時間」は、exactlyの場合は何も明らかにせず、むしろ他の行との関係で行が挿入/変更された場合を明らかにします。

34
Brad

いくつかの追加情報。 RowVersionはbigintに適切に変換されるため、デバッグ時により読みやすい出力を表示できます。

CREATE TABLE [dbo].[T1](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Value] [nvarchar](50) NULL,
    [RowVer] [timestamp] NOT NULL
) 

insert into t1 ([value]) values ('a')
insert into t1 ([value]) values ('b')
insert into t1 ([value]) values ('c')
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1
update t1 set [value] = 'x' where id = 3
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1
update t1 set [value] = 'y' 
select Id, Value,CONVERT(bigint,rowver)as RowVer from t1

Id  Value   RowVer
1   a   2037
2   b   2038
3   c   2039

Id  Value   RowVer
1   a   2037
2   b   2038
3   x   2040

Id  Value   RowVer
1   y   2041
2   y   2042
3   y   2043
13
Peter Meinl

私はこれを使って何かを整理しようとする年齢を費やしました-特定のシーケンス番号の後に更新された列を求めるために。タイムスタンプは実際には単なるシーケンス番号です-BitConverter.ToInt64のようなc#関数がリトルエンディアンを必要とする場合、それはビッグエンディアンでもあります。

エイリアス列「SequenceNo」を使用して、データが必要なテーブルにdbビューを作成してしまいました

SELECT     ID, CONVERT(bigint, Timestamp) AS SequenceNo
FROM         dbo.[User]

c#コードは最初に通常のテーブルと同じようにビュー(つまりUserV)を見つけます

次に、linqでビューと親テーブルを結合して、シーケンス番号と比較できます

var users =  (from u in context.GetTable<User>()
                join uv in context.GetTable<UserV>() on u.ID equals uv.ID
                where mysequenceNo < uv.SequenceNo
                orderby uv.SequenceNo
                select u).ToList();

私が欲しいものを得るために-私が最後にチェックしたときからすべてのエントリが変更されました。

6
user1587804

タイムスタンプのデータ型が悪いと思うのはなぜですか?データ型は、同時実行チェックに非常に役立ちます。 Linq-To-SQLは、まさにこの目的のためにこのデータ型を使用します。

あなたの質問への答え:

1)いいえ。この値は、行が更新されるたびに更新されます。行を5回更新する場合、更新ごとにタイムスタンプ値が増加します。もちろん、「同時に発生する」更新は実際には発生しないことに気づくでしょう。順番に、それらはまだ一度に1つだけ発生します。

2)はい。

5
Randy Minder

注として、timestampはSQL Server 2008以降では非推奨です。代わりにrowversionを使用してください。

MSDNの このページ から:

timestamp構文は非推奨になりました。この機能は、Microsoft SQL Serverの将来のバージョンで削除される予定です。新しい開発作業ではこの機能を使用せず、現在この機能を使用しているアプリケーションの変更を計画してください。

5
Town

Rowversionは、SQLの「理想的な」アプローチの1つを壊します。UPDATEステートメントは単一のアトミックアクションであり、すべてのUPDATE(行内のすべての列とテーブル内のすべての行の両方)が "同時"。ただし、この場合、Rowversionを使用すると、ある行が別の行とは少し異なるタイミングで更新されたと判断できます。

行が(単一のupdateステートメントによって)更新される順序は保証されないことに注意してください。偶然にも、テーブルのクラスター化キーと同じ順序に従う可能性がありますが、私はそれが当てはまるとは限りません。

あなたの質問の一部に答えるには、MSDNによると値が重複する可能性があります。

重複する行バージョン値は、行バージョン列がSELECTリストにあるSELECT INTOステートメントを使用して生成できます。この方法でrowversionを使用することはお勧めしません。

ソース: rowversion(Transact-SQL)

すべてのデータベースには、データベースで行われるすべてのデータ変更に対して1つずつ増加するカウンターがあります。影響を受ける(更新/挿入による)行を含むテーブルにタイムスタンプ/行バージョン列が含まれている場合、データベースの現在のカウンター値は、更新/挿入されたレコードのその列に格納されます。

1
Wolfgang Kais