web-dev-qa-db-fra.com

SQL Server RowVersion / Timestamp - Comparaisons

Je sais que la valeur elle-même pour une colonne RowVersion n'est pas en soi utile, sauf qu'elle change chaque fois que la ligne est mise à jour. Cependant, je me demandais s'ils sont utiles pour la comparaison relative (inégalité).

Si j'ai une table avec une colonne RowVersion, l'une des valeurs suivantes est-elle vraie:

  • Toutes les mises à jour qui se produisent simultanément (même instruction de mise à jour ou même transaction) auront-elles la même valeur dans la colonne RowVersion?
  • Si je mets à jour "A", suivi de la mise à jour "B", les lignes impliquées dans la mise à jour "B" auront-elles une valeur plus élevée que les lignes impliquées dans la mise à jour "A"?

Merci.

27
David Pfeffer

à partir de MSDN :

Chaque base de données possède un compteur incrémenté pour chaque opération d'insertion ou de mise à jour effectuée sur une table contenant une colonne rowversion dans le base de données. Ce compteur est la base de données rowversion. Cela permet de suivre une heure relative dans une base de données, pas une heure réelle qui peut être associée à une horloge. Chaque fois que une ligne avec une colonne rowversion est modifiée ou insérée , la base de données incrémentée rowversion la valeur est insérée dans la colonne rowversion.

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

  • Pour autant que je comprends, rien ne se passe réellement en même temps dans le système. Cela signifie que tous les rowversion doivent être uniques. J'ose dire qu'ils seraient effectivement inutiles si les doublons étaient autorisés dans le même tableau. Donner également crédit aux rowversions qui ne sont pas dupliqués est la position de MSDN de ne pas les utiliser comme clés primaires non pas parce que cela provoquerait des violations, mais parce que cela provoquerait des problèmes de clé étrangère.
  • Selon MSDN, "Le type de données rowversion est juste un nombre incrémenté ..." donc oui, plus tard est plus grand.

À la question de combien il incrémente, MSDN déclare, "[rowversion] suit un temps relatif dans une base de données", ce qui indique qu'il ne s'agit pas d'un incrément entier fluide, mais basé sur le temps. Cependant, ce "temps" ne révèle rien quand exactement, mais plutôt quand par rapport aux autres lignes une ligne a été insérée/modifiée.

34
Brad

Quelques informations supplémentaires. RowVersion se convertit bien en bigint et donc on peut afficher une meilleure sortie lisible lors du débogage:

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

J'ai passé des années à essayer de trier quelque chose avec cela - pour demander des colonnes mises à jour après un numéro de séquence particulier. L'horodatage n'est en réalité qu'un numéro de séquence - il est également bigendien lorsque des fonctions c # comme BitConverter.ToInt64 veulent littleendian.

J'ai fini par créer une vue db sur la table dont je veux des données avec une colonne d'alias 'SequenceNo'

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

le code c # voit d'abord la vue (c'est-à-dire UserV) de façon identique à une table normale

puis dans mon linq je peux rejoindre la vue et la table parent et comparer avec un numéro de séquence

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();

pour obtenir ce que je veux - toutes les entrées ont changé depuis la dernière fois que j'ai vérifié.

6
user1587804

Qu'est-ce qui vous fait penser que les types de données d'horodatage sont mauvais? Le type de données est très utile pour la vérification des accès concurrents. Linq-To-SQL utilise ce type de données à cet effet.

Les réponses à vos questions:

1) Non. Cette valeur est mise à jour à chaque mise à jour de la ligne. Si vous mettez à jour la ligne cinq fois, chaque mise à jour incrémentera la valeur d'horodatage. Bien sûr, vous réalisez que les mises à jour qui "se produisent simultanément" ne le sont vraiment pas. Ils ne se produisent toujours que l'un après l'autre, à leur tour.

2) Oui.

5
Randy Minder

Tout comme une note, timestamp est déconseillé dans SQL Server 2008. rowversion doit être utilisé à la place.

De cette page sur MSDN:

La syntaxe d'horodatage est déconseillée. Cette fonctionnalité sera supprimée dans une future version de Microsoft SQL Server. Évitez d'utiliser cette fonctionnalité dans de nouveaux travaux de développement et prévoyez de modifier les applications qui utilisent actuellement cette fonctionnalité.

5
Town

Rowversion rompt l'une des approches "idéalistes" de SQL: une instruction UPDATE est une action atomique unique et agit comme si toutes les UPDATE (toutes les colonnes d'une ligne et toutes les lignes de la table) se produisaient "à la en même temps". Mais dans ce cas, avec Rowversion, il est possible de déterminer qu'une ligne a été mise à jour à un moment légèrement différent d'une autre.

Notez que l'ordre dans lequel les lignes sont mises à jour (par une seule instruction de mise à jour) n'est pas garanti - il peut, par coïncidence, suivre le même ordre que la clé en cluster de la table, mais je ne compterais pas sur le fait que cela soit vrai.

3

Pour répondre à une partie de votre question: vous pouvez vous retrouver avec des valeurs en double selon MSDN:

Des valeurs de version de ligne en double peuvent être générées à l'aide de l'instruction SELECT INTO dans laquelle une colonne de version de ligne se trouve dans la liste SELECT. Nous ne recommandons pas d'utiliser rowversion de cette manière.

Source: rowversion (Transact-SQL)

2

Chaque base de données possède un compteur qui est incrémenté un par un à chaque modification de données effectuée dans la base de données. Si la table contenant la ligne affectée (par mise à jour/insertion) contient une colonne d'horodatage/version de ligne, la valeur actuelle du compteur de la base de données est stockée dans cette colonne de l'enregistrement mis à jour/inséré.

1
Wolfgang Kais