Fragen zum SQL:LOCK TABLE XYZ in SHARE MODE;
- Dieses Thema hat 5 Antworten und 1 Teilnehmer, und wurde zuletzt aktualisiert vor 12 Jahre, 5 Monaten von
Anonym.
-
AuthorPosts
-
7. April 2011 um 9:44 Uhr #4122
AnonymInaktivHallo zusammen,
seit einigen Tagen grübeln wir über die Funktionsweise und Wirkung des "LOCK TABLE" statements.
Zuerst muss ich mal die Situation erklären.Wir haben eine Protokoll-Tabelle in die alle Programme, die Manipulationen an der Datenbank durchführen, ROWs per INSERT einstellen. Die Tabelle hat ein Attribut TSAEN vom Typ TIMESTAMP, dass mit dem CURRENT TIMESTAMP belegt wird.
Oft ist es erforderlich für eine LUW mehrere Rows zu INSERTen. Diese haben alle einen unterschiedlichen TSAEN.
Leider kann man diesen ROWs aber nicht mehr ansehen, dass sie ursprünglich zu einer LUW gehörten!In bestimmten Abständen greift jetzt eine Anwendung auf die Protokoll-Tabelle zu, um alle Transaktionen seit der letzten Verarbeitung auszulesen. Dabei merkt sich das PGM den Tiemstamp-Alt von der letzten Verarbeitung. Den neuen Timestamp-Neu bildet es sich mit folgender SQL-Abfolge:
1. LOCK TABLE XYZ in SHARE MODE
2. SET :Timestamp-Neu = CURRENT TIMESTAMP
3. COMMITHintergedanke dieses Verfahrens ist es, alle "offenen" Transaktionen auf der Tabelle XYZ zuerst zu beenden und sich dann den CURRENT TIMESTAMP zu holen.
Dadurch erhofften wir uns das dieser SQL immer vollständige Transaktionen aus der Tabelle XYZ ausliest!
SELECT
C1,C2,C3…
FROM XYZ
WHERE TSAEN BETWEEN Timestamp-Alt AND Timestamp-NeuLeider ist das nicht so!!!Wir haben wiederholt Transaktionen, bei denen die erste ROW1
< (älter) als Timestamp-Neu ist
und die ROW2 bis ROWn
> (jünger) als Timestamp-Neu ist.Unser Konzept "nur ganze Transaktionen auszulesen" ist also nicht schlüssig / funktionsfähig!
Wo ist der Denkfehler? Was machen wir falsch?
Für eure Anregungen/Zusatzfragen/Erklärungen besten Dank im Voraus.
Erklärungsversuch des Problems (allerdings ohne Lösung für das Problem):
Bei einem Insert in eine Tabelle, die Timestamp-columns die mit NOT NULL WITH DEFAULT definiert sind, belegt DB2 erstmal die Variablen für den Insert. Dann wird geprüft ob der Insert in die Tabelle stattfinden kann. In unserem Fall ist allerdings der LOCK-Table gerade aktiv. Also wartet DB2 bis der Lock aufgehoben wird (sagen wir mal 2 Sekunden) und INSERTet jetzt den mittlerweile 2 Sekunden alten Timestamp.
Ergebniss: Obwohl der LOCK TABLE um 12:00:00 durchgeführt wurde, gibt es einen INSERT mit Timestamp-Inhalt 11:59:59 Sekunden um 12:00:01.Kann das so sein? Was können wir anders/besser/richtig machen?
Gruss Klaus
7. April 2011 um 16:41 Uhr #4270
AnonymInaktivHallo Klaus,
Dein Erklärungsversuch ist plausibel.
Als Lösungsmöglichkeit fällt mir momentan spontan ein:
a) Das Programm, das die INSERTs macht setzt vor dem ersten INSERT einen LOCK TABLE IN EXCLUSIVE MODE ab
b) Das Programm, das den Timestamp ermittelt, arbeitet mit LOCK TABLE IN EXCLUSIVE MODE und die Programme, die die Inserts machen setzen vorher einen SELECT WITH RR ab.
Gruß
Uli
8. April 2011 um 6:43 Uhr #4376
AnonymInaktivHallo Ulrich,
danke für deine Hinweise.
zu a)
Das sollte gehen, allerdings müssen wir alle Programme ändern, die in die Protokolltabelle schreiben. Außerdem würden diese Programme sich dann serialisieren, da ja alle eine EXCLUSIVE LOCK wollen. Das würde unsere Protokolltabelle zum Nadelöhr machen!
zu b) Verstehe ich nicht ganz. Die Programme wollen nur INSERT machen und ihre eigenen Aktivitäten protokollieren. Was sollen sie nach deinem Vorschlag mit Repeatable Read lesen?
Wir haben in der zwischenzeit ein Testszenarion aufgebaut.
Task 1 ==> 1000 mal INSERT von ROW1 + ROW2 + COMMIT die zu einer LUW gehören (Das ganze in einem ersten DSNTEP2-Job verpackt)
Task 2 ==> 1000 mal LOCK in SHARE MODE + INSERT CURRENT TIMESTAMP in Hilfstabelle + COMMIT (Das ganze in einem zweiten DSNTEP2-Job verpackt)
Beide Jobs parallel gestartet. Läuft ca. 10 Sekunden.
Danach suchen wir mit einem SQL nach Problem-Transaktionen bei denen
TS ROW1 < LOCK-TS (aus Hilfstabelle)
TS ROW2 > LOCK-TS (aus Hilfstabelle)
und ROW1 gehört zur gleichen Transaktion wie ROW2Wir finden immer zwischen 8-20 fehlerhaften Fällen!
Jetzt haben wir testweise Task2 mal geändert:
statt CURRENT TIMESTAMP
machen wir jetzt
SELECT MAX(TS) + 1 MICROSECOND FROM XYZ
und INSERTen den in unsere Hilfstabelle.Resultat: Keine Fehlerfälle mehr vorhanden.
Bei der Erklärung wird es (für uns) schwierig!
Entweder produziert unser Test nicht genügend Last und der Fehler ist nur unwahrscheinlicher geworden und tritt daher nicht mehr auf.
Oder wir haben die DB2-Aktivitäten, die hier im Detail ablaufen, immer noch nicht verstanden.
Warum tritt der Fehler nach eurer Meinung jetzt nicht mehr auf?
Gruß Klaus
8. April 2011 um 19:24 Uhr #4451
AnonymInaktivHallo Klaus,
ich glaube, dass das Phänomen quasi "natürlich" ist: Bei der Deadlock/Timeout Detection Period von 4*15 = 60 Sekunden "stauen" sich die INSERT’s, die nach dem Release/Commit des "Abräumprogramms" dann "endlich" ausgelöst werden. Und diese INSERT’s kommen mit einem Schwall von Timestamps (aus dem datetime special register), der vermeintlich nicht zur Periode passt, die das "Abräumprogramm" bereits abgeräumt hat. Nun wird ja aber der TIMESTAMP nicht ständig neu ermittelt, bis schließlich die physikalische Speicherung der ausstehenden INSERT Requests erfolgreich ist.
Dies würde auch zu Euren Beoachtungen passen. Außerdem: In Zeiten geringer Aktivität wird dieses Phänomen weniger sichtbar.
Das Problem ist, dass Ihr Euch – bislang – auf ein Kriterium verlaßt, dass nicht unique und nicht zuverlässig ist.
Ich würde es mal mit einer ROWID / IDENTITY Column bzw. mit einer SEQUENCE probieren. Dann sorgt DB2 dafür, dass Ihr auf jeden Fall ein eindeutig unterscheidbares Kriterium bekommt.
Ich meine, dass Ihr mit einer SEQUENCE das Reihenfolgen-Problem in den Griff bekommt. (Das "Abräumprogramm könnte die Sequence beispielsweise auch zurücksetzen.)
Viele Grüße
Gernot
8. April 2011 um 19:43 Uhr #4490
AnonymInaktivIch nenn jetzt mal die Programme, die die Inserts machen PGM-A, und das Programm, das den Timestamp ermitteln will PGM-B.
zu meiner Lösung b:
was die PGM-A genau lesen sollen ist irrelevant, solange es etwas aus der Protokoll-Tabelle ist ( das kann z.B. ein Satz mit bestimmtem Schlüssel sein ( timestamp 01:01:0001-00:00:00, oder beliebiger Cursor und ein FETCH).
Es geht ja nur um die Serialisierung gegenüber dem
PGM-B.
Ist eines der PGM-A aktiv, muss das PGM-B wegen seinem LOCK EXCLUSIVE auf das Ende der ganzen Inserts von PGM-A warten.
Andererseits muss bei laufendem PGM-B jedes PGM-A bereits beim Lesen WITH RR warten, so dass der Insert dann mit dem korrekten Timestamp ( größer als von PGM-B ermittelt ) erfolgt.Bei dieser Variante könnten beliebig viele PGM-A laufen, ohne sich gegenseitig zu behindern
15. April 2011 um 14:02 Uhr #4515
AnonymInaktivDanke euch beiden für die Rückmeldungen.
Ich werde mal die Variante mit SEQUENCE ausprobieren.
Vorteile aus meider Sicht:
INSERT-Programme (viele) können unverändert bleiben weil lediglich dass Ausleseprogramm (wenige) die Sequence-von und Sequence-bis Werte bestimmen und auslesen muß.
Reihenfolge für Ausleseprogramm wäre dann:
1. Lock Table in share mode
2. Neu-Sequence-Key-bis bestimmen
3. commit
4. Auslesen BETWEEN letzter-Sequence-Key-bis AND Neu-Sequence-Key-bisDanke.
Gruß Klaus
-
AuthorPosts
You must be logged in to reply to this topic.