Klassifikation von Historien

Je kleiner die Menge, desto eingeschränkter sind die Historien.

seriellstrikt STohne kask. zuru¨ck. ACAru¨cksetzbar RC \small \text{seriell} \sub \text{strikt ST} \sub \text{ohne kask. zurück. ACA} \sub \text{rücksetzbar RC} 

konfliktserialisierbar \Rarr serialisierbar nur ohne abort\small \tt abort

Konflikte

Fehler durch Concurrency wenn auf selben Datensatz zugegriffen wird.

Mindestens eine write-Operation.

ww\tt ww- Lost Update

Update durch die erste Schreiboperation geht durch Überschreibung verloren.

wr\tt wr- Dirty Read

Datensatz wird gelesen, obwohl es nicht commit\small \tt commit ed wurde.

  • DB-Zustand darf während Transaktionen inkonsistent sein.
  • Transaktion könnte später abort\small \tt abort ed werden

rw\tt rw- Unrepeatable Read

Lese-Operation hat bei mehrfacher Ausführung unterschiedliche Ergebnisse

rw\tt rw- Phantomproblem

Gleich aber via count(*)

Klassifikation von Historien

TransaktionTiT_i

(i\small isteht für die Nummer der Transaktion)

Menge an elementaren Operationen mit partieller Ordnung .

DMBS sieht keine Logik:

ri(A)r_i(A)read\small \tt readAA

wi(A)w_i(A)write\small \tt writeAA

cic_icommit\small \tt commit

aia_iabort\small \tt abort

Ohne insert und delete.


Ordnung <i<_i

abort und commit müssen die letzte Aktion sein.

Ordnung muss zwischen allen Operations-Paaren vom selben Datenobjekt definiert sein.

Konflikt-Operation

Paar greift auf das selbe Datenobjekt zu

(ri(A),wj(A)),(wi(A),rj(A)),(wi(A),wj(A)) \left(r_{i}(A), w_{j}(A)\right), \quad\left(w_{i}(A), r_{j}(A)\right), \quad\left(w_{i}(A), w_{j}(A)\right) 

HistorieHH

Eine mögliche execution-order

Ordnung <H<_H

Verträglich mit <i<_i

Ordnung muss zwischen Konfliktoperationen definiert sein.

Seriell

Seriell

T1T2T3T_{1} \mid T_{2} \mid T_{3} \ldots

sequentielle, ununterbrochene Abarbeitung (eine Transaktion nach dem anderen)

Serialisierbar

Serialisierbar (mitabort\small \tt abort)

Ohne abort sind alle Transaktionen bereits erfolgreich abgeschlossen.

Auswirkung der Historie muss auf jeder konsistenten Ausprägung

... identisch zu einer beliebigen seriellen Historie der selben erfolgreich abgeschlossenen Transaktionen sein

Konflikt-Serialisierbar

Serialisierbarkeit = semantische Definition, nicht syntaktisch. Man müsste zum Überprüfen durchjede konsistente Ausprägungdurchiterieren die es gibt.

Konfliktserialisierbar (conflict serializable)

Konfliktäquivalent zu einer seriellen Historie.

  • Beispiel

    Alle diese Historien sind konfliktäquivalent - die letzte ist eine serielle Historie - dadurch sind alle konfliktserialisierbar.

    Sie sind alle über genau 2 Transaktionen und 2 Datenobjekten.

    Konflikte sind nur bei DatenobjektA\small Amöglich.

    r1(A)r2(C)w1(A)w2(C)r1(B)w1(B)c1r2(A)w2(A)c2 \small r_{1}(A) \rightarrow r_{2}(C) \rightarrow w_{1}(A) \rightarrow w_{2}(C) \rightarrow r_{1}(B) \rightarrow w_{1}(B) \rightarrow c_{1} \rightarrow r_{2}(A) \rightarrow w_{2}(A) \rightarrow c_{2} 

    r1(A)w1(A)r2(C)w2(C)r1(B)w1(B)c1r2(A)w2(A)c2 \small r_{1}(A) \rightarrow w_{1}(A) \rightarrow r_{2}(C) \rightarrow w_{2}(C) \rightarrow r_{1}(B) \rightarrow w_{1}(B) \rightarrow c_{1} \rightarrow r_{2}(A) \rightarrow w_{2}(A) \rightarrow c_{2} 

    r1(A)w1(A)r1(B)r2(C)w2(C)w1(B)c1r2(A)w2(A)c2 \small r_{1}(A) \rightarrow w_{1}(A) \rightarrow r_{1}(B) \rightarrow r_{2}(C) \rightarrow w_{2}(C) \rightarrow w_{1}(B) \rightarrow c_{1} \rightarrow r_{2}(A) \rightarrow w_{2}(A) \rightarrow c_{2} 

    r1(A)w1(A)r1(B)w1(B)c1undefinedT1r2(C)w2(C)r2(A)w2(A)c2undefinedT2 \small \underbrace{ r_{1}(A) \rightarrow w_{1}(A) \rightarrow r_{1}(B) \rightarrow w_{1}(B) \rightarrow c_{1}}_{T_1} ~~ \underbrace{ \rightarrow r_{2}(C) \rightarrow w_{2}(C) \rightarrow r_{2}(A) \rightarrow w_{2}(A) \rightarrow c_{2}}_{T_2} 

Konfliktäquivalenz (conflict equivalence)

von 2 Historien (über die selben, nicht abgebrochenen Transaktionen) wenn

... Reihenfolge von allen Konfliktoperationen gleich ist.

(Reihenfolgeinnerhalbeiner Transaktion darf sich nicht ändern)

Serialisierbarkeits-Theorem

H\small H konfliktserilisierbar \LrarrSG(H)\small SG(H) azyklisch


Jede topologische Sortierung von einem azyklischen SG(H)\small SG(H) ist eine konfliktserialisierbare Historie.

  • Beispiel

  • Topologischer Sortierungs-Algorithmus

    In jedem azyklischen gerichteten Graphen gibt es mindestens einen Knoten ohne eingehende Kante.

    In:\small \bold{In}: akzyklischer Serialisierbarkeitsgraph SG(H)\small SG(H)

    Out:\small \bold{Out}: mögliche topologische Sortierung

    1. wähle Knoten Ti\small T_i in SG(H)\small SG(H) ohne eingehende Kante
    1. Schreibe Ti\small T_i in den Output
    1. Lösche Ti\small T_i und alle ausgehenden Kanten
    1. Falls es noch einen Knoten gibt, gehe zum 1. Schritt

Serialisierbarkeits-GraphSG(H)\small SG(H)

Knoten = abgeschlossene Transaktion Ti\small T_i

Gerichtete Kante = TiTj\small T_{i} \rightarrow T_{j} wenn für min einem Konflikt (pi,qj)\small \left(p_{i}, q_{j}\right) gilt pi<Hqj\small p_{i}<_H q_{j}

Konflikt-Serialisierbar \small \Rarr Serialisierbar?

ohneabort\small \tt abort

Konflikt-Serialisierbar \Rarr Serialisierbar

Nicht umgekehrt: Es gibt serialisierbare Historien die nicht konfliktserialisierbar sind.

mitabort\small \tt abort

Konflikt-Serialisierbar ⇏\not\Rarr Serialisierbar

Rücksetzbar

Rücksetzbar

Für alle (Ti,Tj)(T_{i}, ~T_{j}) gilt:

Wenn TiT_{i} von TjT_{j} liest, dann darf TiT_{i} nicht vor TjT_{j}commit\small \tt commit ed werden.

Transaktion darf nur commit\small \tt commit en wenn alle von denen sie gelesen hat auch commit\small \tt commit ed haben.

Lesen:TiT_iliest vonTjT_j

Wenn für min ein Datenobjekt Ti\small T_i genau den Wert liest den Tj\small T_j geschrieben hat:

a)wj(A)<Hri(A)\small w_{j}(A) \textcolor{grey}{<_H} r_{i}(A)

schreib-operation vor lese-operation

b)aj̸<Hri(A)\small a_{j} \textcolor{grey}{\not <_H} r_{i}(A)

kein rücksetzen von Tj\small T_j bevor Ti\small T_i den Wert A\small A gelesen hat

c)wj(A)<Hwk(A)<Hri(A) \small w_{j}(A) \textcolor{grey}{<_H} \textcolor{pink}{w_{k}(A)}\textcolor{grey}{<_H} r_{i}(A)  dann muss es ein ak<Hri(A) \small \textcolor{pink}{a_{k}} \textcolor{grey}{<_H} r_{i}(A)  geben

schreib-operation zwischen schreib- und lese-operation rücksetzen

Ohne kaskadierendes Rücksetzen

Dieses Problem hat man bei der logischen Protokollierung nicht, da man Operationen reversieren kann, aber in der Praxis nutzt man physische Protokollierung.

Historie ohne kaskadierendes Rücksetzen

2 mögliche Definitionen:

  1. Wenn TiT_{i} von TjT_{j} liest, dann muss gelten: cj<Hri(A)c_{j}<_H r_{i}(A)(dann mussTjT_{j}commit\small \tt commited haben)
  1. Änderungen erst nach commit\small \tt commit zum Lesen freigegeben.

Kaskadierendes Rücksetzen

Strikt

Strikte Historie

(Nach jeder schreib-operation muss die Transaktion commited oder aborted werden bevor die nächste Transaktion lesen oder schreibenkann → also auch wenn die nächste Transaktion nicht von der vorherigen liest)

Wenn für ein beliebiges Ti,Tj\small T_{i}, ~T_{j}

gilt

wj(A)<H{ri(A),wi(A)} \small w_{j}(A)\textcolor{grey}{<_H} \left\{r_{i}(A), ~w_{i}(A)\right\} 

dann muss

{cj,aj}<H{ri(A),wi(A)} \small \{c_{j}, ~a_j\}\textcolor{grey}{<_H} \left\{r_{i}(A), ~w_{i}(A)\right\}