2010-05-19 3 views
0

Le tableau output_values_center1 (et un autre) hérite de output_values. Périodiquement, je tronque la table output_values_center1 et charge de nouvelles données (en une transaction). Pendant ce temps, l'utilisateur peut demander des données et il a reçu un message d'erreur. Pourquoi il arrive toujours (sélectionner des requêtes d'interrogation seulement un record) et comment éviter ce problème:Impasse entre select et truncate (postgresql)

2010-05-19 14:43:17 UTC ERROR: deadlock detected 
2010-05-19 14:43:17 UTC DETAIL: Process 25972 waits for AccessShareLock on relation 2495092 of database 16385; blocked by process 26102. 
    Process 26102 waits for AccessExclusiveLock on relation 2494865 of database 16385; blocked by process 25972. 
    Process 25972: SELECT * FROM "output_values" WHERE ("output_values".id = 122312) LIMIT 1 
    Process 26102: TRUNCATE TABLE "output_values_center1" 
+1

pouvez-vous développer les id de relation à partir de ce message d'erreur? c'est-à-dire 'select 2494865 :: regclass' etc – araqnid

+0

merci, la question était plus utile que les réponses, après avoir regardé les relations id j'ai compris où est le problème :) – valodzka

Répondre

1

"TRUNCATE acquires an ACCESS EXCLUSIVE lock on each table it operates on, which blocks all other concurrent operations on the table. If concurrent access to a table is required, then the DELETE command should be used instead."

Il est évident que ce n'est pas clair si vous regardez juste au lien « manpage » au-dessus pourquoi interroger le parent table affecte son descendant. L'extrait suivant de la « page de manuel » pour la commande SELECT clarifie:

"If ONLY is specified, only that table is scanned. If ONLY is not specified, the table and any descendant tables are scanned."

0

Je vais essayer ceci (en pseudocode) pour tronquer:

#define NOWAIT_TIMES 100 
#define SLEEPTIME_USECS (1000*100) 
for (i=0; ; i++) { 
    ok = query('start transaction'); 
    if (!ok) raise 'Unable to start transaction!'; 
    queries = array(
    'lock table output_values in access exclusive mode nowait', 
    'truncate output_values_center1', 
    'commit' 
); 
    if (i>NOWAIT_TIMES) { 
    // we will wait this time, as we tried NOWAIT_TIMES and failed 
    queries[0] = 'lock table output_values in access exclusive mode'; 
    } 
    foreach q in queries { 
    ok = query(q); 
    if (!ok) break; 
    } 
    if (!ok) { 
    query('rollback'); 
    usleep(SLEEPTIME_USECS); 
    } else { 
    break; 
    }; 
}; 

De cette façon, vous serez en sécurité à partir de deadlocks, comme la table parent sera exclusivement verrouillé. Un utilisateur bloquera juste pendant une fraction de seconde tandis que tronquer s'exécute et reprendra automatiquement après la validation.

Mais soyez prêt à ce que cela puisse s'exécuter pendant plusieurs secondes sur un serveur occupé car lorsque la table est utilisée, le verrouillage échouera et sera réessayé.