Comment rendre la fusion sérialisable

en faisant simultanément MERGE s alors que chaque session utilise une valeur différente (indiquée comme *** dans l'extrait ci-dessous) pour la colonne de la clé primaire id , tout va bien si je le fais manuellement en 2 sessions de terminal.

MERGE
 INTO x
   USING (SELECT *** as id FROM DUAL) MERGE_SRC
     ON (x.id = MERGE_SRC.id)
 WHEN MATCHED THEN UPDATE SET val = val + 1 WHERE id = ***
 WHEN NOT MATCHED THEN INSERT VALUES (***, 99);
COMMIT;

cependant, lors d'un essai de charge multi-filetés avec 3 filetages ou plus, je tomberai relativement rapidement sur ORA-08177 with locked table . Pourquoi est-ce? (Et pourquoi est-elle non déterministe en ce sens qu'elle n'est pas toujours se produire lorsque les transactions se chevauchent?)

la table a été créée en utilisant

create table x (id int primary key, val int);

SQL Server btw jamais lève des exceptions avec un équivalent de FUSION instruction, l'exécution de la même expérience. C'est même vrai quand on travaille sur la même rangée simultanément.

est-ce parce que peut-être la fusion est pas atomique , et le mode sérialisable exécute de façon optimiste , donc que la course pourrait seulement montrer avec une réclamation suffisante? Pourtant, pourquoi cela arrive-t-il même si vous ne travaillez pas sur la même rangée en même temps?

Btw, mes tentatives pour corriger ceci en utilisant le verrou le plus strict disponible ont été infructueux. Donc toutes les idées sur la façon de faire cet atomique sont très appréciées. Il semble que le relâchement du niveau d'isolement me débarrasserait de l'exception, mais le risque d'incohérences dans le cas où il s'avère qu'il y a 2 mises à jour sur la même ligne (sinon pourquoi serait-il balk en mode serialisable en premier lieu).

2
demandé sur Community 2013-11-12 11:19:49
la source

2 ответов

L'exception que vous voyez est une conséquence directe de l'utilisation stricte de la sérialisation. Si vous avez plus d'une transaction active simultanément, chacune commencée avec le niveau D'ISOLATION de la TRANSACTION défini sérialisable, lorsque l'une d'elles engage les autres, les autres obtiendront un ORA-08177. C'est ainsi que la sérialisation stricte est imposée - la base de données lance un ORA-08177 dans n'importe quelle session commencée avec le niveau D'ISOLATION sérialisable si une autre transaction s'engage dans une table que la session sérialisable besoin. Donc, en gros, si vous avez vraiment besoin d'une sérialisation stricte, vous devez gérer intelligemment les ORA-08177, comme dans ce qui suit:

DECLARE
  bSerializable_trans_complete  BOOLEAN := FALSE;
  excpSerializable              EXCEPTION;
  PRAGMA EXCEPTION_INIT(excpSerializable, -08177);
BEGIN
  <<SERIALIZABLE_LOOP>>
  WHILE NOT bSerializable_trans_complete
  LOOP
    BEGIN
      SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

      MERGE ...; -- or whatever

      COMMIT;

      bSerializable_trans_complete := TRUE;  -- allow SERIALIZABLE_LOOP to exit
    EXCEPTION
      WHEN excpSerializable THEN
        ROLLBACK;
        CONTINUE SERIALIZABLE_LOOP;
    END;
  END LOOP;  -- SERIALIZABLE_LOOP
END;

la sérialisation n'est pas magique, et elle n'est pas "libre" (où "libre" signifie "Je n'ai rien à faire en tant que développeur pour la faire fonctionner correctement"). Il demande plus de planification et de travail de la part du développeur d'avoir à fonctionner correctement, pas moins. Partagez et profitez.

3
répondu Bob Jarvis 2013-11-12 16:52:24
la source

dans Oracle, le mode SERIALIZABLE fonctionne de manière optimiste, contrairement par exemple à SQL Server, qui fait un verrouillage pessimiste dans ce mode. Ce qui signifie que dans ce dernier cas, vous pouvez même changer simultanément la même ligne sans tomber dans des exceptions.

malgré the docs :

Base de données Oracle permet à une transaction sérialisable modifier une ligne uniquement si des changements à la ligne fait par d'autres les transactions étaient déjà engagées lorsque la transaction de sérialisable a commencé . La base de données génère une erreur lorsqu'une transaction sérialisable tente de mettre à jour ou de supprimer des données modifiées par une transaction différente qui s'est engagée après le début de la transaction sérialisable:

l'essai de charge a montré que les exceptions peuvent aussi être lancées lorsque l'on ne travaille pas simultanément sur la même rangée , bien que cela ne soit pas garanti, en revanche à travailler sur la même rangée, ce qui donnera toujours un ORA-08177 .

2
répondu Eugene Beresovsky 2013-11-13 05:05:40
la source

Autres questions sur