Update: Mögliche Lösung unterPostgres 9.3: SHARELOCK Problem mit einfachen INSERT
Ich habe eine große Korpus von Konfigurationsdateien von Schlüssel/Wert-Paare aus, die ich in eine Datenbank zu schieben bin versucht. Viele der Schlüssel und Werte werden über Konfigurationsdateien hinweg wiederholt, sodass ich die Daten mit 3 Tabellen speichere. Eine für alle eindeutigen Schlüsselwerte, eine für alle eindeutigen Paarwerte und eine, die alle Schlüssel/Wert-Paare für jede Datei auflistet.
Problem: Ich verwende mehrere gleichzeitige Prozesse (und daher Verbindungen), um die Rohdaten in die Datenbank hinzuzufügen. Leider bekomme ich viele Deadlocks beim Versuch, Werte zu den Schlüssel- und Wertetabellen hinzuzufügen. Ich habe eine versucht, ein paar verschiedene Methoden, um die Daten einzufügen (siehe unten), aber immer mit einem „Deadlock erkannt“ am Ende Fehler
TransactionRollbackError: deadlock detected
DETAIL: Process 26755 waits for ShareLock on transaction 689456; blocked by process 26754. Process 26754 waits for ShareLock on transaction 689467; blocked by process 26755.
ich mich gefragt, ob jemand auf genau etwas Licht konnte, was könnte verursachen diese Deadlocks, und möglicherweise weisen mich auf eine Möglichkeit, das Problem zu beheben. Wenn ich mir die SQL-Anweisungen ansehe, die ich verwende (siehe unten), sehe ich nicht wirklich, warum überhaupt eine Co-Abhängigkeit besteht.
Danke fürs Lesen!
Beispiel Konfigurationsdatei:
example_key this_is_the_value
other_example other_value
third example yet_another_value
Tabellendefinitionen:
CREATE TABLE keys (
id SERIAL PRIMARY KEY,
hash UUID UNIQUE NOT NULL,
key TEXT);
CREATE TABLE values (
id SERIAL PRIMARY KEY,
hash UUID UNIQUE NOT NULL,
key TEXT);
CREATE TABLE keyvalue_pairs (
id SERIAL PRIMARY KEY,
file_id INTEGER REFERENCES filenames,
key_id INTEGER REFERENCES keys,
value_id INTEGER REFERENCES values);
SQL-Anweisungen:
Am Anfang war ich versucht, diese Aussage zu verwenden, um alle Ausnahmen zu vermeiden :
WITH s AS (
SELECT id, hash, key FROM keys
WHERE hash = 'hash_value';
), i AS (
INSERT INTO keys (hash, key)
SELECT 'hash_value', 'key_value'
WHERE NOT EXISTS (SELECT 1 FROM s)
returning id, hash, key
)
SELECT id, hash, key FROM i
UNION ALL
SELECT id, hash, key FROM s;
Aber auch etwas so einfach wie dies bewirkt, dass die Deadlocks:
INSERT INTO keys (hash, key)
VALUES ('hash_value', 'key_value')
RETURNING id;
- In beiden Fällen, wenn ich eine Ausnahme geworfen, weil der eingesetzten Hash Wert nicht eindeutig zuzuordnen ist, verwende ich Savepoints um die Änderung rückgängig zu machen und eine andere Aussage, um nur die ID, nach der ich bin, zu wählen.
- Ich Hashes für das einzigartige Feld verwenden, da einige der Schlüssel und Werte sind zu lang, um
Voll Beispiel des Python-Code (mit psycopg2) indiziert wird mit Sicherungspunkten:
key_value = 'this_key'
hash_val = generate_uuid(value)
try:
cursor.execute(
'''
SAVEPOINT duplicate_hash_savepoint;
INSERT INTO keys (hash, key)
VALUES (%s, %s)
RETURNING id;
'''
(hash_val, key_value)
)
result = cursor.fetchone()[0]
cursor.execute('''RELEASE SAVEPOINT duplicate_hash_savepoint''')
return result
except psycopg2.IntegrityError as e:
cursor.execute(
'''
ROLLBACK TO SAVEPOINT duplicate_hash_savepoint;
'''
)
#TODO: Should ensure that values match and this isn't just
#a hash collision
cursor.execute(
'''
SELECT id FROM keys WHERE hash=%s LIMIT 1;
'''
(hash_val,)
)
return cursor.fetchone()[0]
Update: So glaube ich, dass ich einen Hinweis auf another stackexchange site:
Insbesondere:UPDATE, DELETE, SELECT FOR UPDATE, and SELECT FOR SHARE commands behave the same as SELECT in terms of searching for target rows: they will only find target rows that were committed as of the command start time1. However, such a target row might have already been updated (or deleted or locked) by another concurrent transaction by the time it is found. In this case, the would-be updater will wait for the first updating transaction to commit or roll back (if it is still in progress). If the first updater rolls back, then its effects are negated and the second updater can proceed with updating the originally found row. If the first updater commits, the second updater will ignore the row if the first updater deleted it2, otherwise it will attempt to apply its operation to the updated version of the row.
Während ich noch nicht ganz sicher bin, wo die Co-Abhängigkeit ist, scheint es, dass eine große Anzahl von Schlüssel/Wert-Paare Verarbeitung ohne commiting in so etwas wie dies wahrscheinlich zur Folge hätte. Sicher genug, wenn ich festlege, nachdem jede einzelne Konfigurationsdatei hinzugefügt wurde, treten die Deadlocks nicht auf.
Eine andere Alternative wäre, die Werte immer in der gleichen Reihenfolge einzufügen. –