2010-01-21 13 views
1

J'utilise mySQL à partir de leur API C, mais cela ne devrait pas être pertinent. Mon code doit traiter les enregistrements d'une table qui correspondent à certains critères, puis mettre à jour lesdits enregistrements pour les marquer comme traités. Les lignes de la table sont modifiées/insérées/supprimées par un autre processus que je ne contrôle pas. Je crains dans ce qui suit, la mise à jour peut signaler quelques enregistrements par erreur puisque l'ensemble de la correspondance des dossiers pourrait avoir changé entre l'étape 1 et l'étape 3.SQL (mySQL) mettre à jour une certaine valeur dans tous les enregistrements traités par un select

SELECT * FROM myTable WHERE <CONDITION>; # step 1 
<iterate over the selected set of lines. This may take some time.> # step 2 
UPDATE myTable SET processed=1 WHERE <CONDITION> # step 3 

Quelle est la façon intelligente de veiller à ce que UPDATE met à jour toutes les lignes traitées, et seulement eux? Une transaction ne semble pas correspondre à la facture car elle ne fournit pas d'isolation de ce type: un enregistrement récemment modifié ne figurant pas dans l'ensemble sélectionné à l'origine peut toujours être ciblé par l'instruction UPDATE. Pour la même raison, SELECT ... FOR UPDATE ne semble pas aider, bien que cela semble prometteur :-)

La seule façon que je peux voir est d'utiliser une table temporaire pour mémoriser l'ensemble des lignes à traiter , en faisant quelque chose comme:

CREATE TEMPORARY TABLE workOrder (jobId INT(11)); 
INSERT INTO workOrder SELECT myID as jobId FROM myTable WHERE <CONDITION>; 
SELECT * FROM myTable WHERE myID IN (SELECT * FROM workOrder); 
<iterate over the selected set of lines. This may take some time.> 
UPDATE myTable SET processed=1 WHERE myID IN (SELECT * FROM workOrder); 
DROP TABLE workOrder; 

Mais cela semble inutile et pas très efficace.

Y a-t-il quelque chose de plus intelligent?

Merci beaucoup d'un débutant SQL.

Répondre

1

J'ai finalement résolu ce problème en utilisant une colonne dans ce tableau que les drapeaux des lignes en fonction de leur statut. Cette colonne me permet d'implémenter une machine à états simple. Conceptuellement, j'ai deux valeurs possibles pour ce statut:

kNoProcessingPlanned = 0; #default "idle" value 
kProcessingUnderWay = 1; 

Maintenant, mon algorithme fait quelque chose comme ceci:

UPDATE myTable SET status=kProcessingUnderWay WHERE <CONDITION>; # step 0 

SELECT * FROM myTable WHERE status=kProcessingUnderWay; # step 1 
    <iterate over the selected set of lines. This may take some time.> # step 2 
UPDATE myTable SET processed=1, status=kNoProcessingPlanned WHERE status=kProcessingUnderWay # step 3 

Cette idée d'avoir des lignes dans plusieurs états peut être étendue à autant d'états que nécessaire .

1

Il y a plusieurs options:

  1. Vous pouvez verrouiller la table

  2. Vous pouvez ajouter un ET foo_id IN (all_the_ids_you_processed) comme condition de mise à jour.

  3. vous pouvez mettre à jour avant de sélectionner et seulement sélectionner les lignes mises à jour (à savoir par date de traitement)

+0

1- Verrouiller la table signifie empêcher l'autre processus de fonctionner pendant le traitement. Ce ne serait pas heureux ... 2- Sans table temporaire, comment pouvez-vous exprimer all_the_ids_you_trocessed? 3- Je me sens un peu mal à l'aise d'horodater les documents traités à l'avance pour pouvoir les sélectionner plus tard car ils sont invasifs: une nouvelle colonne "timeStamp" est nécessaire. En outre, les horodatages sont difficiles, car le temps n'est pas toujours monotone: il peut par exemple régresser (lorsque l'heure d'été se déclenche par exemple). Là encore, la table temporaire est-elle vraiment une mauvaise idée? –

+0

Au lieu de l'horodatage, utilisez un champ d'état à plusieurs valeurs. Laisser les lignes non traitées avoir le statut 0 (disons); vous effectuez une mise à jour pour définir l'état sur 1 (en cours de traitement) sur vos lignes sélectionnées, puis effectuez le traitement, puis effectuez une autre mise à jour pour définir l'état sur 2 (traitement inné). –

+0

oui je suppose que cela peut fonctionner dans le problème comme je l'ai décrit. Mais j'ai finalement décidé de mémoriser les identifiants des enregistrements traités dans l'application cliente. –

Questions connexes