... 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)
Produktnr
Bezeichnung
Preis
Bewertung
17
Schokoriegel
0.89
4.5
29
Spülmaschinentabs
3.99
2.0
Logische Ebene
Produktnr
Bezeichnung
Preis
17
Schokoriegel
0.89
29
Spülmaschinentabs
3.99
Kundennr
Produktnr
Bew
5
17
4
8
17
5
5
29
2
Physische Ebene: 0010110000000100101111010101...
Sichten / Views in SQL
94-96
Produktnr
Bezeichnung
Preis
Hersteller
Bewertung
17
Schokoriegel
0.89
Monsterfood
4.5
18
Müsliriegel
1.19
Monsterfood
-
29
Spülmaschinentabs
3.99
Calgonte
2.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.
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');
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.
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.
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
Dirty Read
Non‑Repeatable Read
Phantomproblem
Read Uncommitted
möglich
möglich
möglich
Read Committed
nicht mögl.
möglich
mö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.