8
votes

MS SQL DateTime Problème de précision

J'ai une situation où deux personnes peuvent travailler sur le même ordre (stockées dans une base de données MS SQL) de deux ordinateurs différents. Pour prévenir la perte de données dans le cas où on permettrait d'économiser sa copie de la commande, puis un peu plus tard, la seconde sauverait sa copie et écraserait le premier, j'ai ajouté un chèque contre le lastaved champ (DateTime) avant d'économiser.

Le code semble grossièrement comme ceci: xxx

Cela fonctionne pendant la plupart du temps, mais j'ai trouvé un petit bug.

si orderischangedbyTherUser renvoie false , la copie locale aura son mise à jour mise à jour à l'heure actuelle, puis être persisté à la base de données . La valeur de lastavued dans la copie locale et la DB devrait maintenant être la même. Toutefois, si orderischangedbyTherUser est exécuté à nouveau, il retourne parfois vrai même si aucun autre utilisateur n'a apporté de modifications à la base de données.

lors du débogage dans Visual Studio , base de donnéesOrdonOrder.lastsaved et localOrderCopy.lastsaved semble avoir la même valeur, mais lorsque vous regardez de plus près, ils diffèrent par quelques millisecondes.

i trouvé Cet article avec un bref préavis sur la précision de milliseconde pour DateTime en SQL:

Un autre problème est que SQL Server stocke DateTime avec une précision de 3,33 millisecondes (0,00333 secondes).

La solution que je pourrais penser à ce problème est de comparer les deux denttimes et de les considérer comme étant égales si elles diffèrent de moins de 10 millisecondes.

Ma question est alors : Y a-t-il des moyens meilleurs / plus sûrs de comparer deux valeurs DateTime dans MS SQL pour voir s'ils sont exactement les mêmes?


1 commentaires

Juste pour spécifier: je n'ai pas la possibilité de modifier le type de champ lastavued , donc je vais devoir rester à DateTime.


7 Réponses :


0
votes

Vous pouvez utiliser un champ horodatage pour vérifier la dernière date d'édition plutôt qu'un champ DateTime? (Dans SQL 2008, ceci est maintenant Rowversion)


2 commentaires

Pourrait être une possibilité, mais je n'ai pas la possibilité de modifier le type du champ LastSaved.


Vous n'êtes pas obligé. Ajoutez un champ supplémentaire pour cela. Modifiez ensuite la mise à jour SP pour vérifier à la fois le champ PK et la version de la ligne. Vous obtiendrez 0 rangées affectées si la version de la ligne a changé alors.



0
votes

Vous devez vous assurer que votre temps de précision de votre temps - ceci est principalement faisable en ayant la logique appropriée du côté C pour réduire réellement la précision de celle qui est originaire de l'objet DateTime - faites fondamentalement SUER que vous avez par exemple des horodatages toujours en quelques secondes, pas plus bas, sur toutes les couches.

Si vous le faites correctement, l'horodatage de toutes les couches sera immédiatement comparable.


0 commentaires

2
votes

Vous pouvez ajouter un champ de révision entier à votre table de commande. Chaque fois qu'un utilisateur enregistre la commande que vous augmentez la révision par une. Ensuite, il est facile de vérifier si quelqu'un a modifié la commande ou si l'utilisateur souhaitait enregistrer la commande est sur la dernière révision.


0 commentaires

1
votes

tandis que vous êtes dans SQL 2005 et avant que le problème de précision ne soit toujours présent, jamais plus précis que 1/300e de seconde, ou 3.33ms.

Quel que soit le manque de précision, vous programmez une condition de course imparfaite où les deux utilisateurs peuvent toujours écrire dans la base de données de succession rapide, mais les deux sont considérés comme successivement. L'absence de précision augmente les chances de celui-ci, tant que les écritures de contrôle et de suivantes se sont produites dans les mêmes 3-4 ms.

Toute tentative de vérification suivie d'une écriture souffre de ce problème et que vous devez accepter les conséquences d'un verrouillage optimiste, modifiez le verrouillage sur pessémistique ou implémenter une forme de stratégie de type sémaphore pour gérer correctement le verrouillage.


1 commentaires

Je suis au courant de la logique potentiellement imparfaite, mais comme avec de nombreux systèmes anciens, il suffit de vivre avec. J'ai eu un petit espoir qu'il pourrait y avoir un moyen de faire, mais je pense que nous pourrions être capable de vivre avec une précision de 0,33 ms.



7
votes

Je sais que vous avez dit que vous ne pouvez pas changer le type, mais s'il s'agit uniquement de maintenir la compatibilité et de votre utilisation de 2008, vous pouvez modifier le champ lastSaved sur DateTime2 ( qui est entièrement compatible avec DateTime ) et utilisez sysdateTime () dont les deux ont beaucoup plus de précision.


1 commentaires

Je n'étais pas au courant de DateTime2. Mes serveurs de test sont au moins exécutant SQL Server 2008, de sorte que cela pourrait être une option. Il suffit de vous assurer que tous ceux qui utilisent le système sont également sur 2008 ... merci :)



0
votes

Il y a une autre façon de faire cela potentiellement.

Au lieu de passer dans la "dernière sauvegarde" de la machine locale, modifiez la procédure stockée de la mise à jour. Attribuer LastSaved = getDate () Puis renvoyez la valeur de LastSaved (et de tout autre résultats, tels que IDS), et mettez à jour le temps lastavué au client avec ce résultat.

Il y a deux avantages évidents à cela. L'un est que votre précision DateTime est préservée. L'autre est que la date et l'heure sont désormais cohérentes avec le serveur, plutôt que de souffrir de toute latence réseau et des problèmes de dérive d'horloge locale.

Nous utilisons habituellement SPS générées automatiquement pour les opérations de CRUD, et les tableaux fonctionnent généralement "créés / lâchés" et "CrééBy / LastUpdatedated" paires où les dates sont définies sur le serveur, et les valeurs "par" sont transmises et Si NULL est défini sur System_user


0 commentaires

0
votes

Vérifiez la version de compatibilité à SQL 2014 - Modification de SQL 2016 Convertit DateTime en DateTime2 (7) dans la structure d'entité.

voir MSN .

Essayez ce SQL pour tester sur votre carte et votre colonne de votre ordinateur: xxx


0 commentaires