2010-05-28 2 views
4

J'utilise la table avec un compteur pour assurer des identifiants uniques sur un élément enfant. Je sais qu'il est généralement préférable d'utiliser une séquence, mais je ne peux pas l'utiliser parce que j'ai beaucoup de compteurs (un client peut créer un couple de seaux et chacun d'eux doit avoir son propre compteur, ils doivent commencer par 1 (c'est une exigence, mon client a besoin de clés « lisibles par l'homme »).Oracle (PL/SQL): UPDATE RETOUR est-il simultané?

Je crée des documents (Appelons les articles) qui ont un prikey (bucket_id, num = contre).

Je dois garantir que la combinaison bucket_id/num est unique (donc utiliser une séquence comme prikey ne résoudra pas mon problème)

La création de ro ws ne se produit pas en pl/sql, donc je dois réclamer le nombre (btw: ce n'est pas contre les exigences d'avoir des lacunes).

Ma solution a été:

UPDATE bucket 
     SET counter = counter + 1 
    WHERE id = param_id 
RETURNING counter INTO num_forprikey; 

retours PL/SQL var_num_forprikey de sorte que le dossier de l'article peut être créé.

Question:

Est-ce que je toujours obtenir num_forprikey unique, même si l'utilisateur demande en même temps de nouveaux éléments dans un seau?

+0

Je pense, mais je ne trouve pas la documentation à ce sujet !! – Jaap

Répondre

6

Aurais-je toujours num_forprikey unique, même si l'utilisateur demande simultanément nouveaux éléments dans un compartiment?

Oui, au moins jusqu'à un certain point. Le premier utilisateur à émettre cette mise à jour obtient un verrou sur la ligne. Aucun autre utilisateur ne peut donc émettre cette même instruction jusqu'à ce que l'utilisateur numero uno valide (ou annule). Donc, l'unicité est garantie.

Évidemment, le cavil concerne la concurrence. Votre accès à la ligne est sérialisé, il n'y a donc aucun moyen pour deux utilisateurs d'obtenir un nouveau PRIKEY simultanément. Ce n'est pas nécessairement un problème. Cela dépend du nombre d'utilisateurs pour lesquels vous créez de nouveaux éléments et de la fréquence à laquelle ils le font. Un utilisateur qui enlève des numéros dans la même session ne remarquera rien.

+3

APC dit la vérité. Cependant, c'est une excellente façon de bloquer votre application si une session ne COMMANDE pas la mise à jour. –

0

Je trouverais comment faire fonctionner les séquences. Il est la seule garantie, si une clause d'exception pourrait être codé

http://www.orafaq.com/forum/t/83382/0/ L'avantage à des séquences (et ils pourraient être créé de façon dynamique, est que vous pouvez spécifier nocache et de l'ordre de garantie)

+0

Chaque seau devrait avoir son propre compteur, donc je ne peux pas utiliser de séquences! – Jaap

+0

Créer des séquences dynamiquement n'est pas une option, car il y aura beaucoup de seaux ... – Jaap

1

Il me semble me rappeler ce problème depuis de nombreuses années en travaillant sur une base de données INGRES. Il n'y avait pas de séquences à cette époque, donc beaucoup d'efforts ont été déployés pour trouver la meilleure solution d'échelle pour ce problème par les meilleurs esprits d'INGRES du jour. J'ai eu la chance de travailler à côté d'eux de telle sorte que même si mon esprit est pitoyablement plus petit que l'un des leurs, la proxi- mité = affect résiduel et j'ai retenu quelque chose. C'était l'une des choses. Laissez-moi voir si je peux me souvenir. La raison de la validation est d'essayer d'obtenir une sorte d'évolutivité. Il y aura toujours une limite mais vous ne sérialiserez pas en obtenant un nombre pour n'importe quelle période de temps.

Dans le monde des oracles, nous améliorerions la situation en utilisant une fonction définie comme AUTONOMOUS_TRANSACTION afin d'acquérir le numéro suivant. Si vous y réfléchissez, cette solution nécessite que des écarts soient autorisés, ce que vous avez dit être OK. En validant la mise à jour du numéro indépendamment de la transaction principale, vous gagnez de l'évolutivité, mais vous introduisez le gapping.

Vous devrez accepter le fait que votre évolutivité diminuera considérablement dans ce scénario. Ceci est dû à au moins deux raisons:

1) la séquence update/select/commit fait de son mieux pour réduire le temps pendant lequel la ligne KEY est verrouillée, mais elle n'est toujours pas nulle. Sous une lourde charge, vous allez sérialiser et éventuellement être limité. 2) vous vous engagez sur chaque clé. Une validation est une opération coûteuse qui nécessite de nombreuses actions de gestion de la mémoire et des fichiers de la part de la base de données. Cela vous limitera aussi. En fin de compte, vous êtes probablement confronté à une baisse de trois ordres de grandeur ou plus de la charge de transaction simultanée, car vous n'utilisez pas de séquences. Je base ceci sur mon expérience du passé.

Mais si votre client l'exige, que pouvez-vous faire correctement?

Bonne chance. Je n'ai pas testé le code pour les erreurs de syntaxe, je vous laisse ça.

create or replace function get_next_key (key_name_p in varchar2) return number is 
    pragma autonomous_transaction; 
    kev_v number; 
begin 

    update key_table set key = key + 1 where key_name = key_name_p; 

    select key_name into key_name_v from key_name where key_name = key_name_p; 

    commit; 

    return (key_v); 

end; 
/
show errors