Comment IDENTITY_INSERT affecte-t-il la concurrence?


11

J'essaie d'aider un client avec un module complémentaire SAP tiers qui a un problème de publication et est devenu sans support.

Dans certaines circonstances, il archive et poste incomplet de la table de file d'attente de publication vers la table d'archive de publication. Je dois replacer ces résultats archivés dans la file d'attente.

L'ID de file d'attente est une colonne d'identité et je voudrais qu'elle reste la même.

La question est, si je fais identité_insertion activée / insertion / identité_insertion désactivée, à quoi puis-je m'attendre en ce qui concerne la concurrence avec les processus qui créent les entrées de file d'attente et s'attendent à ce que la colonne d'identité soit générée automatiquement?

Tous les conseils sur la meilleure façon de démontrer un tel comportement seraient également grandement appréciés.

Réponses:


8

La définition IDENTITY_INSERT ONseule n'élimine pas la concurrence - cela ne place aucun verrou exclusif sur la table, seulement un bref verrou de stabilité de schéma (Sch-S).

Donc, ce qui pourrait théoriquement se produire, avec le comportement par défaut, c'est que vous pourriez le faire dans la session 1:

BEGIN TRANSACTION;

-- 1
SET IDENTITY_INSERT dbo.tablename ON;

-- 2
INSERT dbo.tablename(id, etc) VALUES(100, 'foo'); -- next identity is now 101

-- 3
INSERT dbo.tablename(id, etc) VALUES(101, 'foo'); -- next identity is now 102

-- 4
SET IDENTITY_INSERT dbo.tablename OFF;

COMMIT TRANSACTION;

Dans une autre session, vous pouvez insérer des lignes dans le tableau aux points 1, 2, 3 ou 4. Cela peut sembler une bonne chose, sauf ce qui se passe pour toute insertion qui se produit entre 2 et 3, c'est que la valeur générée automatiquement déclenchée par une autre session est basée sur les résultats de l'instruction 2 - elle générera donc un 101, puis l'instruction 3 échouera avec une violation de clé primaire. C'est assez simple à configurer et à tester vous-même avec quelques WAITFORs:

-- session 1
-- DROP TABLE dbo.what;
CREATE TABLE dbo.what(id INT IDENTITY PRIMARY KEY);
GO
BEGIN TRANSACTION;

SET IDENTITY_INSERT dbo.what ON;

INSERT dbo.what(id) VALUES(32);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(33);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(34);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(35);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(36);

SET IDENTITY_INSERT dbo.what OFF;

COMMIT TRANSACTION;

Une fois ce lot démarré, démarrez ce lot dans une autre fenêtre:

-- session 2
INSERT dbo.what DEFAULT VALUES;
WAITFOR DELAY '00:00:01';
GO 20

La session 2 ne devrait jamais insérer que des valeurs de 1 à 20, non? Sauf que parce que l'identité sous-jacente a été mise à jour par votre session d'insertions manuelles 1, à un moment donné, la session 2 reprendra là où la session 1 s'est arrêtée, et insérera 32, ou 33, ou 34 etc. Il sera autorisé à le faire, mais alors la session 1 échouera à l'insertion suivante avec une violation de PK (que l'on gagne peut être juste une question de timing).

Une façon de contourner ce problème consiste à appeler un TABLOCKsur la première insertion:

INSERT dbo.what WITH (TABLOCK) (id) VALUES(32);

Cela bloquera tout autre utilisateur essayant d'insérer (ou de faire quoi que ce soit, vraiment) avec ce tableau jusqu'à ce que vous ayez terminé de reculer ces lignes archivées. Cela limite la concurrence, bien sûr, mais c'est ainsi que vous souhaitez que le blocage fonctionne. Et j'espère que ce n'est pas quelque chose qui se produit à un rythme si fréquent où vous bloquez d'autres personnes tout le temps.

Quelques autres solutions:

  • arrêtez de vous soucier de la IDENTITYvaleur générée. On s'en fout? Utilisez un UNIQUEIDENTIFIER(peut-être généré dans un tableau séparé avec un IDENTITYcomme substitut) si la valeur d'origine est très importante.
  • changer le processus d'archivage pour utiliser une «suppression logicielle» où quelque chose est marqué comme archivé initialement et l'archivage n'est rendu permanent qu'à une date ultérieure. Quel que soit le processus qui tente de les reculer, il suffit d'effectuer une mise à jour directe et de corriger l'indicateur de suppression logicielle.

Merci pour ton explication. J'écris un utilitaire autonome pour aider avec un produit hors support qui crée ces champs d'identité. Je n'ai aucun contrôle sur son fonctionnement.
Métaphore
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.