Prof. Dr.-Ing. Johannes Schildgen
johannes.schildgen@oth-regensburg.de

Datenbanken

Kapitel 5: Mehrbenutzerbetrieb

2020-12-11

In diesem Kapitel...

  • ... definieren wir Sichten,
  • ... lernen, wie man DB-Benutzer und Rollen verwaltet,
  • ... schauen wir uns das Transaktionenkonzept genauer an,
  • ... erfahren wir, wie man Mehrbenutzeranomalien vermeidet
  • ... und wie Recovery-Mechanismen funktionieren.

Datenabstraktion

Externe Ebene (Sichten / Views)

Sicht auf eine Teilmenge des
logischen Schemas für eine
bestimmte Benutzergruppe

Logische Ebene

DB-Gesamt-Schema

Physische Ebene

Internes Schema / Speicherung der Daten

Sicht

Sicht

Sicht

log. Schema

int. Schema

Datenabstraktion (Bsp.)

Externe Ebene (View für Webshop-Anwendung)

ProduktnrBezeichnungPreisBewertung
17Schokoriegel0.894.5
29Spülmaschinentabs3.992.0

Logische Ebene

ProduktnrBezeichnungPreis
17Schokoriegel0.89
29Spülmaschinentabs3.99
KundennrProduktnrBew
5174
8175
5292

Physische Ebene: 0010110000000100101111010101...

Sichten / Views in SQL

94-96
ProduktnrBezeichnungPreisHerstellerBewertung
17Schokoriegel0.89Monsterfood4.5
18Müsliriegel1.19Monsterfood-
29Spülmaschinentabs3.99Calgonte2.0
CREATE VIEW produkte_view AS
SELECT P.produktnummer, P.bezeichnung, P.preis, P.hersteller, 
       AVG(B.sterne) AS bewertung
FROM produkte P LEFT JOIN bewertungen B 
     ON P.produktnummer = B.produktnummer
GROUP BY P.produktnummer, P.bezeichnung, P.preis, P.hersteller
                        
SELECT * FROM produkte_view

Views / Sichten in SQL

CREATE VIEW teure_produkte AS SELECT * FROM produkte 
                               WHERE preis > 10;
SELECT * FROM teure_produkte WHERE hersteller = 'Monsterfood'

wird ausgeführt als:

SELECT * FROM (SELECT * FROM produkte WHERE preis > 10)
WHERE hersteller = 'Monsterfood'
                        

SELECT * FROM produkte WHERE preis > 10 AND hersteller = 'Monsterfood'

  • Liefert etwas komplett anderes
  • Gibt das gleiche zurück, ist aber schneller
  • Gibt das gleiche zurück, ist aber langsamer
  • Gibt das gleiche zurück und ist gleich schnell

https://frage.space

Einsatzszenarios von Views

Vereinfachung / Speicherung von Anfragen

CREATE VIEW produkte_view AS ... 

Datenunabhängigkeit

Anwendungen greifen über View auf Daten zu; unabhängig, wie die tatsächlichen Tabelle aussehen.

Datenschutz

Benutzern wird nur der Zugriff auf die View gewährt, nicht auf die zugrundeliegenden Tabellen.

CHECK OPTION

106

INSERT, UPDATE und DELETE sind auf simplen Projektion/Selektion-Views erlaubt.

CREATE VIEW teure_produkte AS SELECT * FROM produkte 
                            WHERE preis > 10;

INSERT / UPDATE funktioniert ohne Überprüfung des WHERE-Prädikats.

WITH CHECK OPTION

CREATE VIEW teure_produkte AS SELECT * FROM produkte 
                            WHERE preis > 10 WITH CHECK OPTION;

Das einzufügende oder zu ändernde Tupel muss das WHERE-Prädikat erfüllen.

INSERT INTO teure_produkte (produktnr, bezeichnung, preis) VALUES (123, 'X', 5)

  • funktioniert nie
  • funktioniert in den beiden hier gezeigten Sichten nicht
  • funktioniert in der oberen, aber nicht in der unteren Sicht
  • funktioniert in der unteren, aber nicht in der oberen Sicht

https://frage.space

Materialisierte Sichten

98

Views sind nur virtuell, sie speichern nicht wirklich Daten.

Materialisierte Sichten jedoch speichern physisch das Ergebnis der dahinterstehenden Anfrage.

CREATE MATERIALIZED VIEW anz_produkte AS 
SELECT COUNT(*) as anz FROM produkte;

REFRESH MATERIALIZED VIEW

SELECT * FROM anz_produkte; -- zeigt an: 8
INSERT INTO produkte (produktnr, bezeichnung) values (123, 'X'); 
SELECT * FROM anz_produkte; -- zeigt immer noch 8
REFRESH MATERIALIZED VIEW anz_produkte;
SELECT * FROM anz_produkte; -- zeigt nun 9

Benutzer und Rollen

97
CREATE USER doktor_x WITH PASSWORD 'geheimespasswort1';
CREATE USER schwester_y WITH PASSWORD 'geheimespasswort2';
CREATE USER big_boss WITH PASSWORD 'geheimespasswort3';
CREATE USER ninja WITH PASSWORD 'geheimespasswort4';
                        

Benutzer und Rollen

CREATE ROLE klinikpersonal;
GRANT klinikpersonal TO doktor_x, schwester_y;
CREATE ROLE mitarbeiter;
GRANT mitarbeiter TO big_boss, klinikpersonal;
CREATE ROLE finanzen;
GRANT finanzen TO big_boss;
                          

GRANT: Berechtigung erteilen

97

GRANT <Recht> ON <Objekt> TO <Benutzer oder Rolle>

--Mitarbeiter dürfen sich mit der Datenbank verbinden
GRANT CONNECT ON klinik_db TO mitarbeiter;
--Die Finanzabteilung darf die Tabelle Reisekosten lesen
GRANT SELECT ON klinik.reisekosten TO finanzen;
--Doktor X darf alles auf der Patienten-Tabelle machen
GRANT ALL PRIVILEGES ON klinik.patienten TO doktor_x;
--Schwester Y darf Patienten einsehen, erstellen und ändern
GRANT SELECT, INSERT, UPDATE ON klinik.patienten TO schwester_y;
GRANT SELECT ON ALL TABLES IN SCHEMA klinik TO big_boss;
GRANT SELECT ON klinik.raeume TO PUBLIC; -- Das darf jeder

REVOKE: Berechtigung entziehen

GRANT SELECT ON klinik.raeume TO PUBLIC;
CREATE VIEW klinik.raeume_view AS
SELECT * FROM klinik.raeume WHERE gebaeude IN (10,12,13,15);
                        

REVOKE <Recht> ON <Objekt> FROM <Benutzer oder Rolle>

REVOKE SELECT ON klinik.raeume FROM PUBLIC;
GRANT SELECT ON klinik.raeume_view TO PUBLIC;

Alle Benutzer außer Peter sollen ein SELECT auf T machen dürfen.

  • GRANT SELECT ON T TO PUBLIC; REVOKE SELECT ON T FROM Peter;
  • Rolle R erstellen, in der alle außer Peter sind. GRANT SELECT ON T TO R;
  • Das geht nicht

https://frage.space

GRANT OPTION

Das Privileg, ein Privileg weiterzugeben.

GRANT SELECT ON ALL TABLES IN SCHEMA klinik TO big_boss
WITH GRANT OPTION;
REVOKE GRANT OPTION FOR SELECT ON ALL TABLES IN SCHEMA klinik 
FROM big_boss; -- nur GRANT OPTION entziehen, nicht das Recht

REVOKE ... RESTRICT | CASCADE

REVOKE SELECT ON ALL TABLES IN SCHEMA klinik FROM big_boss 
RESTRICT; -- nur, wenn es nicht weitergegeben wurde
REVOKE SELECT ON ALL TABLES IN SCHEMA klinik FROM big_boss
CASCADE; -- auch allen, denen es weitergegeben wurde

Transaktionen

111

ACID

  • Atomarität
  • Konsistenz
  • Isolation
  • Dauerhaftigkeit

Commit / Rollback

112-113

Mit einer commit-Operation beendet man eine Transkation.
rollback beendet ebenfalls die Transkation, sie führt jedoch zum Abort, sodass alle Änderungen rückgängig gemacht werden.

Autocommit

DB-Anwendungen setzen Autocommit-Einstellung. Bei SQL-Clients wie dem DBeaver ist Autocommit standardmäßig an.

DBeaver Autocommit

Autocommit bedeutet, dass ein Commit automatisch wann ausgeführt wird?

  • nach jeder Transaktion
  • nach jeder SQL-Anfrage
  • beim Schließen der DB-Verbindung
  • alle Paar Sekunden

https://frage.space

Atomarität

Eine TA wird entweder ganz oder gar nicht ausgeführt.

INSERT INTO hersteller VALUES ('Dogdog', 'England');
INSERT INTO produkte VALUES (129, 'Hundefutter', 8.95, 'Dogdog');
COMMIT;
INSERT INTO hersteller VALUES ('Techbob', 'USA');
INSERT INTO produkte VALUES (129, 'Laptop', 999.99, 'Techbob');

SQL-Fehler [23505]: ERROR: duplicate key value violates unique constraint "produkte_pkey" Detail: Key (produktnummer)=(129) already exists.

⇒ Die TA kann komplett zurückgerollt werden, sodass der Hersteller Techbob auch nicht eingefügt wird.

Konsistenz

Eine TA führt die Datenbank von einem konsistenten Zustand in wieder einen konsistenten Zustand.

INSERT INTO produkte VALUES (129, 'Laptop', 999.99, 'Techbob');

SQL-Fehler [23505]: ERROR: duplicate key value violates unique constraint "produkte_pkey" Detail: Key (produktnummer)=(129) already exists.

Alle geltenden Integritätsbedingungen müssen zum Ende einer Transaktion erfüllt sein: Primärschlüssel-, Fremdschlüssel-, UNIQUE-, NOT NULL-, CHECK-Constraints, etc.

Isolation

Parallel laufendende Transaktionen beeinflussen sich nicht.

Mehrbenutzeranomalien

  • Dirty Read: TA2 liest noch nicht committete Änderungen von TA1
  • Lost Update: TA1 und TA2 schreiben gleichzeitig; wer gewinnt?
  • Non-repeatable Read: TA liest mal veraltete und mal aktualisierte Werte
  • ...

Ziel: Gefühlter Einbenutzerbetrieb!

Dirty Read

TA1
SELECT preis FROM produkte 
WHERE produktnr = 17; -- 0.89 EUR

UPDATE produkte
SET preis = 0 
WHERE produktnr = 17;



ROLLBACK;
TA2






SELECT preis FROM produkte
WHERE produktnr = 17; -- 0 EUR
COMMIT;

Was ist hier Dirty?

  • TA1
  • TA2
  • Der Preis von Produkt 17
  • Rollback

https://frage.space

Lost Update

TA1
SELECT preis FROM produkte 
WHERE produktnr = 17; -- 0.89 EUR

UPDATE produkte
SET preis = preis + 0.1
WHERE produktnr = 17; -- 0.99 EUR
  
COMMIT;
TA2
SELECT preis FROM produkte
WHERE produktnr = 17; -- 0.89 EUR

UPDATE produkte
SET preis = preis + 0.1
WHERE produktnr = 17; -- 0.99 EUR

COMMIT;

Non-repeatable Read

TA1
SELECT preis FROM produkte 
WHERE produktnr = 17; -- 0.89 EUR
    



SELECT preis FROM produkte 
WHERE produktnr = 17; -- 0.99 EUR
  
COMMIT;

Was macht TA2?

  • INSERT ...;
  • UPDATE ...;
  • INSERT ... ; COMMIT;
  • UPDATE ...; COMMIT;

https://frage.space

TA2


UPDATE produkte
SET preis = preis + 0.1
WHERE produktnr = 17; -- 0.99 EUR
COMMIT;




Phantomproblem

TA1
SELECT * FROM produkte 
WHERE hersteller = 'Monsterfood';
-- 2 Produkte werden angezeigt
    



SELECT COUNT(*) FROM produkte 
WHERE hersteller = 'Monsterfood';
-- Ergebnis: 3
  
COMMIT;
TA2



INSERT INTO produkte
VALUES (..., 'Monsterfood');
COMMIT;






Serialisierbarkeit

Jede Transaktion besteht aus Lese- und Schreibaktionen: $r_1(x), r_1(y), w_1(x), c_1$

Serieller Ablauf

Keine verzahnte Ausführung, z. B. $r_1(x), r_1(y), w_1(x), c_1, r_2(z), r_2(x), c_2, r_3(y), c_3$

Serialisierbarkeit ("Final-State-serialisierbar")

Ablauf ist serialisierbar, wenn Anfragen das gleiche Ergebnis liefern und DB im gleichen Zustand hinterlassen wird, wie bei irgendeinem seriellen Ablauf.

Serialisierbarkeit ("Konflikt-serialisierbar")

Ablauf ist serialisierbar, wenn es keine Zyklen im Serialisierbarkeitsgraphen gibt.

Serialisierbarkeitsgraph

Konfliktoperationen

  • r → w
  • w → r
  • w → w

Von verschiedenen TAs auf gleichem Objekt.

Im Serialisierbarkeitsgraphen sind die TA die Knoten und es gibt eine Kante von einer TA zu einer anderen, wenn Konfliktoperationen zwischen diesen existieren.

Serialisierbarkeitsgraph

Beispiel: $r_1(x), w_1(y), r_2(x), w_1(x), w_3(y), w_3(x), c_1, c_2, c_3$

Konfliktoperationen hier:

  • $r_1(x) \rightarrow w_3(x)$
  • $w_1(y) \rightarrow w_3(y)$
  • $r_2(x) \rightarrow w_1(x)$
  • $r_2(x) \rightarrow w_3(x)$
  • $w_1(x) \rightarrow w_3(x)$

TA1

TA2

TA3

Kein Zyklus im Serialisierbarkeitsgraphen ⇒ Der Ablauf ist serialisierbar

Äquivalenter serieller Ablauf: TA2, TA1, TA3

Serialisierbarkeitsgraph

Anderes Beispiel: $r_1(x), w_1(x), r_2(x), w_1(x), w_3(y), w_3(x), c_1, c_2, c_3$

Konfliktoperationen hier:

Welches ist hier eine Konfliktoperation?

  • r1(x) → w1(x)
  • r2(x) → w1(x)
  • r1(x) → w3(y)
  • r1(x) → r2(x)

https://frage.space

  • $r_1(x) \rightarrow w_3(x)$
  • $w_1(x) \rightarrow r_2(x)$
  • $w_1(x) \rightarrow w_3(x)$
  • $r_2(x) \rightarrow w_1(x)$
  • $r_2(x) \rightarrow w_3(x)$
  • $w_1(x) \rightarrow w_3(x)$

Zyklus im Serialisierbarkeitsgraphen ⇒ Der Ablauf ist nicht serialisierbar

TA1

TA2

TA3

SX-Sperrverfahren

Sperrverfahren werden eingesetzt, um Serialisierbarkeit zu erreichen. Bevor eine TA ein Objekt liest oder schreibt, muss es dies mit einer Sperre versehen.

Sperrmatrix

 SX
S-
X--

SX-Sperrverfahren

Beispiel: $r_1(x), r_2(x), c_1, c_2$

TA1TA2Gesetzte Sperren
$r_1(x)$$S_1(x)$
$r_2(x)$$S_{1,2}(x)$
$c_1$$S_2(x)$
$c_2$

SX-Sperrverfahren

Beispiel: $r_1(x), w_1(x), r_2(x), w_1(x), w_3(y), w_3(x), c_1, c_2, c_3$

TA1TA2TA3Gesetzte Sperren
$r_1(x)$$S_1(x)$
$w_1(x)$$X_1(x)$
warten$X_1(x)$
$w_1(x)$warten$X_1(x)$
warten$w_3(y)$$X_1(x), X_3(y)$
wartenwarten$X_1(x), X_3(y)$
$c_1$wartenwarten$X_3(y)$
$r_2(x)$warten$S_2(x), X_3(y)$
$c_2$warten$X_3(y)$
$w_3(x)$$X_3(x), X_3(y)$
$c_3$

Was kommt als nächstes?

  • TA2 liest x
  • TA2 setzt S-Sperre auf x
  • TA2 muss warten, bis TA1 x fertig geschrieben hat
  • TA2 muss warten, bis TA1 committed hat

https://frage.space

Deadlocks

Beispiel: $r_1(x), r_2(y), w_2(x), w_1(y), c_1, c_2$

TA1TA2Gesetzte Sperren
$r_1(x)$$S_1(x)$
$r_2(y)$$S_1(x), S_2(y)$
warten$S_1(x), S_2(y)$
wartenwarten$S_1(x), S_2(y)$

TA2 wartet auf TA1 und umgekehrt ⇒ Deadlock

Lösung: Eine der TAs muss vom TMS zurückgesetzt werden.

SQL-Isolationslevels

  • Read Committed
  • Read Uncommitted
  • Repeatable Read
  • Serializable
DBeaver Autocommit
Dirty ReadNon‑Repeatable ReadPhantomproblem
Read Uncommittedmöglichmöglichmöglich
Read Committed nicht mögl.möglichmöglich
Repeatable Read nicht mögl.nicht mögl.möglich
Serializable nicht mögl.nicht mögl.nicht mögl.

Lost Updates werden stets verhindert, sie sind in allen Iso'levels nicht möglich.

Was ist der Grund, warum man mal ein lockereres Isolationslevel als Serializable wählen könnte?

  • Sicherheit
  • Performanz
  • Bessere Erfüllung von ACID
  • Man will alte Werte lesen

https://frage.space

Multi-Version-Concurrency-Control

  • Ein Objekt (Tabelle, Zeile, Wert, ...) kann in mehreren Versionen existieren.
  • TA schreibt: $w_1(x)$ ⇒ neue Version $x'$ anlegen
  • TA liest: $r_2(x)$ ⇒ alte Version $x$ wird gelesen
  • TA committet: $c_1$ ⇒ neue Version wird gültig und sichtbar für andere TAs

Beispiel (nicht Konflikt-serialisierbar): $r_1(x), w_1(x), r_2(x), w_1(x), c_1, c_2$
↖ TA2 liest alte Version

Das ist äquivalent zu folgendem und somit doch Konflikt-serialisierbar:
$r_1(x), r_2(x), w_1(x), w_1(x), c_1, c_2$

Recovery-Mechanismen

Transaktionen müssen auch bei TA-, System- und Hardwarefehlern ACID-konform ausgeführt werden (atomar, ..., dauerhaft).

Aus Performance-Gründen schreiben TAs erst einmal Änderungen nur im RAM; von Zeit zu Zeit werden die geänderten Blöcke dann auf die Festplatte ge-flush-t.

Alle Änderungen einer TA werden aber in ein Transaktions-Log eingetragen, welches immer spätestens bei einem Commit auf die Platte geschrieben wird.

LSNTAPageIDUndoRedoPrevLSN
27TA1xUndo-InfoRedo-Info22

Transaktionsfehler

Beispiel: $r_1(x), r_2(y), r_1(z), w_1(x), w_2(y), w_1(z), a_1, c_2$

LSNTAPageIDUndoRedoPrevLSN
1TA1BOT---
2TA2BOT---
3TA1xUndo-InfoRedo-Info1
4TA2yUndo-InfoRedo-Info2
5TA1zUndo-InfoRedo-Info3
6TA1Abort--5
7TA2Commit--4

Systemfehler

Beispiel: $r_1(x), r_2(y), r_1(z), w_1(x), w_2(y), w_1(z), c_1,$ ↯ Crash!

LSNTAPageIDUndoRedoPrevLSN
1TA1BOT---
2TA2BOT---
3TA1xUndo-InfoRedo-Info1
4TA2yUndo-InfoRedo-Info2
5-Flush---
6TA1zUndo-InfoRedo-Info3
7TA1Commit--6

Was bedeutet der Flush?

  • Gepufferte Seiten werden auf die Platte geschrieben
  • Alle Transaktionen committen
  • Seiten werden von der Festplatte in den DB-Puffer geladen
  • Der DB-Puffer wird geleert

https://frage.space

Checkpoints

Regelmäßig legt die Datenbank Sicherungspunkte (Checkpoints) an.

  • Geänderte DB-Seiten im Puffer werden auf die Platte persistiert (Flush)
  • Vorteil: Recovery beginnt beim letzten Checkpoint

Varianten:

  • Transaktionskonsistente Checkpoints
  • Aktionskonsistente Checkpoints
  • Unscharfe (Fuzzy) Checkpoints

Transaktionskonsistente Checkpoints

Checkpoint wird angelegt, wenn keine Transaktion läuft.

  1. Anmeldung, dass nun ein Checkpoint angelegt werden soll
  2. Warten, bis alle laufenden TAs abgeschlossen sind
  3. Neu startende TAs müssen warten
  4. Wenn keine TA mehr läuft, gepufferte DB-Seiten persistieren

Aktionskonsistente Checkpoints

Beim Anlegen des Checkpoints werden aktuell laufende TAs pausiert.

Fuzzy Checkpoints

  • Kein Flush von geänderten Seiten
  • Checkpoint beinhaltet nur Infos über aktuell laufende TAs und den Puffer-Zustand (welche Seiten sind dirty?)
  • Recovery beginnt bei Min(DirtyLSN)
  • Flush von beliebigen Seiten kann asynchron zu beliebiger Zeit erfolgen

MinDirtyPageLSN

Kapitelzusammenfassung

  • Sichten: CREATE VIEW ... AS
  • WITH [LOCAL|CASCADED] CHECK OPTION
  • Materialisierte Sichten / REFRESH
  • Benutzer und Rollen
  • GRANT / REVOKE
  • ACID-Transaktionen
  • Mehrbenutzeranomalien (Dirty Read, Lost Update, ...)
  • Serialisierbarkeit / Serialisierbarkeitsgraph
  • SX-Sperrverfahren
  • Isolationslevels
  • MVCC
  • Recovery / Transaktions-Log
  • Checkpoint-Recovery