und schemalose DBS

Werbung
OR-MAPPER / JPA
Persistentes Objektmodell im Programm
Layers: RDBMS ->JDBC Driver(JDBC Driver(Third Party)) -> JDBC API(Standard JDBC Interface)->JPA Provider(JPA Implementierung(
Third Party))->Java Persistence API (Standard ORM Interface (JEE)-> Java Program(Applikation mit pers. Objekten)
Entities als persistente Objekte, POJO, Abbildung zur DB mit Annotations oder XML-File
getter und setter nötig, kann erben und vererben, kann interfaces und abstract. Public odo prot.; Konstr ohne Argumente, keine
finals, fields private odo prot. Default 1:1 Mapping; JPA-Conf: persistence-unit: name=Class; Angaben von Connstringparameter
Schemaerstellungapproaches: Top down(businessmodel->db), Bottom up(db->business), middle-out(metadaten->db und business),
meet middle
@Entity: Klasse persistieren; @Id: Primary key, @Table(name=“tablename“), @Column(name=“columnnameindb“, unique=bool,
optional=false, length=200, scale=10, precision=2) //alles ausser name optional
@GeneratedValue bei Id (Strategy=GenerationType[AUTO,IDENTITY,SEQUENCE,TABLE]), @Temporal(TemporalType.TIMESTAMP,
DATE, TIME) > Infos für Date/Time typen, Enums : Annotation mit @Enumerated(EnumType.STRING) , @Transient;nicht
gespeichert;
Unterstützt: Prim, Wrapper,Str,Enum,Byte/CharArray, Date, Cal, SerializableKlassen; Relationen:Collection von Entities, Referenzen
Property Access : Annotation bei Getter, Bei Boolean auch isX
Mapping: @OneToOne(optional=true), @JoinColumn(name=“namewieindb“, referencedColumName=“name“ insertable=bool,
updatable=bool),
@OneToOne(mappedBy=“attrnameinotherclass“) //invers, bezieht sich auf Attrubut in referenzierender Klasse
@ManyToOne(optinal=bool)@JoinColumn(name=“customerref“)
@OneToMany @JoinColumn(name=‘’dbfieldinrefernzierterklasse’’, referencedColumnName=’’EigenerPrimaryKeyInCode)
@ManyToMany @JoinTable(name=“tablenameindb’’, joinColumns = {@JoinColumn(name=’’eigenerefinjointable’’)},
inverseJoinColumns = {@JoinColumn(name=’’Andererefinjointable’’)})
@ManyToMany(mappedBy =‘‘bankCustomers‘‘) //Hier AttributName im Code der anderen Klasse, über der ManyToMany steht
->name muss jeweils wie in db geschrieben sein
Beispiel CRUD:
EntityManagerFactory factory = Persistence.createEntityManagerFactory(‘’Bank’’) ; EntityManager em =
factory.createEntityManager() ; //Neue Session !; Query query = em.createQuery(‘select a from BankAccount a’) ;
List<BankAccount> l = query.getResultList() ;em.close() //besser mit finally
Create : em.getTransaction().begin() ; BankCustomer c = new BankCustomer() ; c.setName(‚Bill‘);em.persist(c);
em.getTransaction().commit();em.close()
Update : //in transaction wrappen : BankAccount a = em.find(BankAccount.class, 1L)//Suche durch Primary key ;
account.incBalance(200);
Delete : //in transaction wrappen : em.remove(customer) ;
Refresh: em.refresh(customer) -> In Datenbank anpassen
Eager Loading: Target direkt laden, default by OneToOne ManyToOne, Lazy: erst wenn Zugriff. @OneToOne(fetch = FetchType.LAZY)
Persistence Unit Menge von Entity Klassen und deren Mapping Bestimmt JPA Provider und DB-Anbindung Durch META-INF /
persistence.xml beschrieben
EntityManagerFactory Verwaltet eine Persistence Unit
Persistence Context Verwaltet Menge von Entity Instanzen zur Laufzeit
Entity ist managed => in Persistence Context Entity new oder detached => gehört zu keinem Context Definiert transaktionelle Session
Entity Manager Verwaltet Persistence Con text Bietet Lifecycle-Operationen für Entity Instanzen an
Abbildung, Typ-Diskriminator -> Sind immer nur bei Parentklasse zu notieren! Ausser natürlich Diskriminator-value
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) : Default, Alle Unterklassen in Obeklassen, effizient, Unnötigee Nulls,
diskriminator nötig
@DiscrimatorColumn(name= »type ») //Bei Parentklasse
@DiscriminatorValue(« Retail ») //Bei Childklasse
InheritanceType.Joined : Jede Klasse abgebildet und Joined, Viele Tabellen, Komplizierter, Diskriminator nötig, keine unnötige
Columns -> Hierbei ist es noch nötig, bei allen Subklassen das Attribut @PrimaryKeyJoinColumn(name="idInParent") zu setzen, bei
der Parentklasse wie folgt den Diskriminator vorzubereiten: @DiscriminatorColumn(name="type", discriminatorType
=DiscriminatorType.STRING), @DiscriminatorValue(‘‘DistinctValue‘‘) Bei Kind
TABLE_PER_CLASS: Oberklasse und Unterklasse, Gemeinsames Attributmapping, Nachteile bei Query Probleme mit Ordering Joins
Relation mit Abhänbgigkeiten:
@OneToMany(cascade=CascadeType.PERSIST, REMOVE)
Konsistenz->wenn n :m Beziehung Konsistenz sein sollen, dann sollte man dies über add/remove Methoden jeweils überprüfen
Dynamic Queries Anfragen mit JPQL: Übersetzt in SQL. Beispiel: -> Alle Klassennamen und Attribute wie in Code schreiben !!!
Query q = em.createQuery(Select a from BankCustimer c join c.accounts a); select distict a.id, a.balance from BankAccount a where
a.balance > 0 order by a.balance.desc
Query Params : select a from BankAccount a where a.customer.name like ?1 ; select a from BankAccount a where a.customer.name
like :name ; query.setParameter(1, « bob »), query.setParameter(« name », « Marc »), Verhinderung SQL Injection
Query query = em.createQuery(« SELECT c FROM BANKCustomer c where c.name like :customerName ») ;
query.setParameter(« customername », name) ; query.setMaxResults(1000) ; List<BankCustomer> list = query.getResultList() ;
NamedQuery bei Klasse @NamedQuery(name= »x », query= ‘’SELECT c.name, SUM(a.balance) FROM BankCustomer c JOIN
c.bankAccounts a GROUP BY c.name") ; em.createNamedQuery(« x ») ; vorgeparst optimiert -> Mit List<Object[]> list =
query.getResultList() ; Beim iterieren dann mit index[0], index[1] Zugriff
->Namen von Attributen und Tablenamen immer so schreiben wie im Code definiert, nicht wie in Tabellen!
Em.getransaction().begin()/.commit() ; Locking mit em.lock(entity, LockModeTyoe.PESSIMISTIC_WRITE)
Beispiel Locking :
em.getTransaction().begin(); BankAccount from =em.find(BankAccount.class, fromAccountId); BankAccount to =
em.find(BankAccount.class, toAccountId); em.lock(from, LockModeType.PESSIMISTIC_WRITE); em.lock(to,
LockModeType.PESSIMISTIC_WRITE); from.setBalance( from.getBalance() - amount); to.setBalance(to.getBalance() + amount);
em.getTransaction().commit();em.refresh(from); em.refresh(to);
STORED PROCEDURES
Konsistenzprüfung, nahe bei Daten, Sicherheit(Verfeinerter Zugriffsschutz, Sicherheitsprüf mit Triggers, Auditing von Zugriffen mit
Triggern), Datenbankobjekte, Aus anderen SP, Triggern, PL/SQL-Blöcken, Clientappl aufrufbar; Rechte: Grant Execute on Funktion to
userxy; +: Alle Überprüfungen zentral, Zugriff nur via Prozduren, Verbessert Leistungsfähigkeit im Client-Server
Zugriffsschutz mit Stored Procedures: Benutzer modifiziert über SP Daten, SP kapsen Daten und implementieren, Benutzer
benötigen keine Privilegien für Modifikation der darunterliegenden Tabelle, Procedures laufen mit Rechten ihres Erstellers, Sollten
vom Owner der Tabellen erstellt werden
Procedure hat keinen Returnvalue und kann nicht in SQL gerufen werden, Function beides!
Prozedur-Parameter
In Postgresql: Eine Stored Procedure ist immer eine Funktion!
CREATE [OR REPLACE] FUNCTION name ( [argname] argtype [,…]]) [RETURNS rettype | RETURNS TABLE (colname coltype [,…] ) ] AS
$$ ..source.. $$ LANGUAGE plpgsql
Ausgaben: RAISE NOTICE ‘Hello World!‘;
CREATE OR REPLACE FUNCTION suche(matrnr numeric(10)) RETURNS void AS $$
DECLARE name varchar(30); semester numeric(2);
BEGIN
SELECT s.name, s.semester INTO name, semester FROM students s WHERE s.matrnr = matrnr;
IF (name IS NULL) THEN RAISE NOTICE ‘Leider nicht gefunden‘; ELSE RAISE NOTICE ‘Name: %, Semester: %‘, name, semester; END IF;
END;
$$ LANGUAGE plpgsql;
SELECT suche(0620611);
CREATE OR REPLACE FUNCTION pow_mod(bigx bigint, n bigint, m bigint) RETURNS bigint AS $$
DECLARE x bigint; xx bigint;
BEGIN
IF n = 0 THEN RETURN 1; END IF; X:= bigx % m; Xx:=(x*x) % m; IF n % 2 = 0 THEN RETURN pow_mod(xx, n/2, m); ELSE
RETURN (x * pow_mod(xx, (n-1)/2, m)) %m; END IF; END; $$ LANGUAGE plpgsql;
PL/SQL(prozed. Sprache mit eingebettetem SQL
Variable: nach DECLARE; Block: BEGIN .. END; Konstante: CONSTANT; Fehler anzeigen: SHOW ERRORS
Beispiel:
DECLARE Emp_name VARCHAR2(10); Emp_number INTEGER; Empno_out_of_range EXCEPTION;
BEGIN
Emp_number := 10001 ;
IF Emp_number > 9999 OR Emp_number < 1000 THEN RAISE Empno_out_of_range ;
ELSE
SELECT Name INTO Emp_name FROM Angestellter WHERE PersNr = Emp_number ;
DBMS_OUTPUT.PUT_LINE(‚Employee name is ‘|| Emp_name) ;
END IF ;
EXCEPTION
WHEN Empno_out_of_range THEN
DBMS_OUTPUT.PUT_LINE(‘Employee number ‘ || Emp_number || ‘is out of range.’) ;
END ;
- Employee number 10001 is out of range
When: Fehlerbehandlung: TOO_MANY_ROWS, NO_DATA_FOUND, DUP_VAL_ON_INDEX
Beispiel:
CREATE OR REPLACE FUNCTION ZeitAnteilSumme (AngNr IN INTEGER, TotProzAnt OUT INTEGER)
RETURNS INTEGER AS $$
BEGIN
SELECT COALESCE(SUM( Zeitanteil ), 0) INTO TotProzAnt FROM Projektzuteilung pzt WHERE pzt.PersNr = AngNr;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION AngInProjekt (AngId IN INTEGER, ProjId IN INTEGER)
RETURNS INTEGER AS $$
DECLARE
p_n Projektzuteilung.ProjNr%TYPE:=-1;
BEGIN
SELECT (ProjNr, -1) INTO p_n FROM ProjektZuteilung WHERE PersNr = AngId AND ProjNr = ProjId; RETURN p_n;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION ProjektZuteilen (AngId IN INTEGER, ProjId IN INTEGER, ProzAnt IN DECIMAL, StartZeit IN DATE,
ResCode OUT INTEGER)
AS $$
DECLARE
TotProzAnt ProjektZuteilung.Zeitanteil%TYPE; RealStartZeit DATE;
BEGIN
ResCode := 1; /*ok*/
IF( ProzAnt < 10 OR ProzAnt > 90 ) THEN ResCode := -1; RETURN; END IF;
IF( AngInProjekt (AngId, ProjId) > 0 ) THEN ResCode := -3; RETURN; END IF;
select ZeitAnteilSumme(AngId) into TotProzAnt;
IF( (TotProzAnt + ProzAnt) > 100 ) THEN ResCode := -2; RETURN; END IF;
IF( StartZeit IS NULL ) THEN RealStartZeit := now() ELSE RealStartZeit := StartZeit; END IF;
INSERT INTO ProjektZuteilung VALUES ( AngId, ProjId, ProzAnt, RealStartZeit, NULL );
RETURN;
EXCEPTION
WHEN OTHERS THEN
ResCode := -4; /*Ang oder Proj nicht vorhanden */
END;
$$ LANGUAGE plpgsql;
-- Test
DO LANGUAGE plpgsql $$ DECLARE errcode DECIMAL:=0; zanteil integer:=0;
BEGIN select projektzuteilen(1100, 25, 10, Null) into errcode; raise notice 'errcode: %', errcode; END; $$
NR bearbeitete rows: SQL%ROWCOUNT/NOTFOUND
Funktionen (haben Rückgabewert)
CREATE OR REPLACE FUNCTION AbteilungsSalaer (AbtName VARCHAR2)
RETURNS NUMBER
IS
AbtSalaer NUMBER (10,2) := 0;
BEGIN
SELECT sum(A.salaer) INTO AbtSalaer FROM Angestellter A, Abteilung Abt WHERE A.AbtNr = Abt.AbtNr AND Abt.Name = AbtName;
RETURN AbtSalaer;
End AbteilungSalaer;
Anstatt IS kann man auch AS schreiben. Aufruf, Verwendung in SQL:
SELECT Name, AbteilungSalaer(Name) FROM Abteilung WHERE AbteilungSalaer(Name) > 40000
Aufruf aus PL/SQL:
DECLARE TotSalaer Number; BEGIN TotSalaer := AbteilungSalaer(‚Entwicklung‘); Dbms_output.put_line(‚Salaer Entwicklung ‚ ||
TotSalaer); END;
Weitere Variablen, die man benötigt, kann man nach dem IS deklarieren
Baublöcke:
IF (a = 10) THEN … ELSIF (a = 20 ) THEN .. ELSE .. END IF;
FOR Counter in 1..20 // Mit FOR c IN REVERSE 1..15 startet c bei 15…
LOOP X := Counter * 31; END LOOP;
MOD(15, 4) ->3; MOD(15, 0) ->15;
WHILE a > 1000 LOOP … END LOOP;
Datentyp boolean gibt es, logische Operatoren: AND, OR, NOT
Operationen auf String: LENGTH(myString), select SUBSTR(<string to parse>,<start position>,(<length>)) //Index startet bei 1!!!
Stored Procedurs in pl/pgsql
Bei OUT-Parametern diese nicht im Declare teil initialisieren!Erschafft neue Variable im Scope, die äussere ist dann null
ELSEIF wird hier zusammen geschrieben!!
DROP FUNCTION IF EXISTS fn3(int) ;
CREATE OR REPLACE FUNCTION fn3(_persnr IN angestellter.persnr%TYPE, startZeit date DEFAULT current_date) RETURNS int –
RETURNS void bei PROZEDUR !
AS $$
DECLARE
Aname angestellter.name%TYPE ; Abtnr angestellter abtne%TYPE;
BEGIN
SELECT a.name, a.abtnr INTO aname, abtnr FROM angestellter a WHERE presnr = _persnr;
RAISE NOTICE ‚DEBUG: NAME %; Abt.: %‘, aname, abtnr; --DEBUG / Warnung, bricht nicht ab
RETURN abtnr; --RAISE SQLSTATE ‚22012‘; --User defined Exception!
END ; $$ LANGUAGE plpgsql ;
--Test Aufruf (Auch bei Prozeduren :
SELECT fn3(1002);
--Prozedur mit OUT Parametern:
CREATE OR REPLACE FUNCTION myfn(myparam OUT int; pyparam2 out int)
AS $$ BEGIN Myparam := 1 ; Myparam2 := 2 ; END ; $$ LANGUAGE plpgsql ;
--AUFRUF :
SELECT myparam FROM myfn() ; SELECT * FROM myfn() ;
SELECT = functioktioniert nicht, immer SELECT INTO var bla….;
Cursor: Handle or name for a private SQL area an area in memory inside db server in which a parsed statement, procedures or
functions or kept; Problem bei erwähnten Zuweisungen von Tabellenwerten: funktioniert nur bei single-row-select; Abhilfe Cursors:
Arbeiten sämtliche Tupel aus dem Ergebnis nacheinander ab-> Select-Statement liefert in Regel Menge von Tupels(Result Set)->
Cursor erlaubt sequentiellen Zugriff auf die einzelnen Tupels; Zyklus: Deklaration, Open, Fetch while not empty, close
Normaler Cursor:
DECLARE CurrAbtNr integer := 1; CURSOR AngCursor IS SELECT Salaer, PersNr, FROM Angestellter WHERE
Angestellter.AbtNr=CurrAbtNr; SalSumme NUMBER(8, 2) := 0; AngSalaer Angestellter.Salaer%Type; AngPersNr
Angestellter.PersNr%Type;
BEGIN
OPEN AngCursor // SQL Abfrage starten und Resultate in Puffer
LOOP FETCH AngCursor INTO AngSalaer, AngPersNr; EXIT WHEN NOT FOUND
SalSumme := SalSumme + AngSalaer;
END LOOP;
ClOSE AngCursor
Mit Params:
DECLARE CurrAbtNr integer; CURSOR AngCursor (ABtId in Abteilung.AbtNr%TYPE) IS SELECT Salaer, PersNr, FROM Angestellter
WHERE Angestellter.AbtNr=CurrAbtNr; SalSumme NUMBER(8, 2) := 0; AngSalaer Angestellter.Salaer%Type; AngPersNr
Angestellter.PersNr%Type;
BEGIN
FOR CurrAbtNr IN 1..2
LOOP
OPEN AngCursor(CurrAbtNr);
LOOP FETCH AngCursor INTO AngSalaer, AngPersNr; EXIT WHEN NOT FOUND
SalSumme := SalSumme + AngSalaer;
END LOOP;
ClOSE AngCursor
AngCursor%ROWTYPE -> Liefert Typ des Tupels -> NUR ORACLE!!!!
Cursor for Update:
CURSOR AngCursor IS SELECT Salaer, Chef, PersNr FROM Angestellter WHERE Angestellter.AbtNr=CurrAbtNr FOR UPDATE;
OPEN AngCursor;
LOOP
FETCH AngCursor INTO AngRec //Positioniert Cursor auf das aktuelle Tupel, es wird gesperrt EXIT WHEN NOT FOUND
UPDATE Angestellter SET Salaer = MinSaler WHERE CURRENT OF AngCursor; // Ändert das durch den Cursor refernzierte Tupel
END LOOP;
CLOSE AngCursor;
Cursor mit Delete:
LOOP
FETCH GruppenCursor INTO gruppe,punktezahl; EXIT WHEN NOT FOUND;Punktezahl := punktezahl * 2;
DELETE FROM Gruppen WHERE CURRENT OF GruppenCursor; INSERT INTO Gruppen VALUES(gruppe, punktezahl); END LOOP;
Cursor Postgres:
DROP TABLE IF EXISTS Top5;
CREATE TABLE Top5 (Name
VARCHAR(20), Persnr NUMERIC, Salaer DECIMAL(7,2);
truncate Top5;
DO LANGUAGE plpgsql $$
DECLARE
c1 CURSOR IS SELECT name, persnr, salaer FROM angestellter ORDER BY salaer DESC; -- start with highest-paid angestellter
my_name CHAR(20); my_persnr NUMERIC; my_salaer NUMERIC(7,2);
BEGIN
OPEN c1;
FOR i IN 1..5 LOOP
FETCH c1 INTO my_name, my_persnr, my_salaer;
EXIT WHEN NOT FOUND; /* in case the number requested is more than the total number of employees */
INSERT INTO top5 VALUES (my_name, my_persnr, my_salaer);
END LOOP; CLOSE c1;END; $$
Ref Cursor in Schema; PostgreSQL
CREATE SCHEMA ANGPACKAGE AUTHORIZATION anguser;
CREATE FUNCTION ANGPACKAGE.AbteilungsAngestellte(Abteilungsnummer IN INTEGER) RETURNS refcursor AS $$
DECLARE ref refcursor;
BEGIN OPEN ref FOR select * from angestellter ang where ang.AbtNr = Abteilungsnummer; RETURN ref; END;
$$ LANGUAGE plpgsql;
DO LANGUAGE plpgsql $$
DECLARE
AbtNr integer := 3; thecursor refcursor; angrec Angestellter%rowtype; abtname Abteilung.Name%TYPE;
BEGIN
select ANGPACKAGE.AbteilungsAngestellte(AbtNr) into thecursor;
LOOP
fetch NEXT from thecursor into angrec;
EXIT WHEN NOT FOUND;
select name into abtname from abteilung a where a.abtnr=angrec.abtnr;
raise notice 'Angestellter: % Abteilung: %', angrec.PersNr, abtname;
END LOOP;
END;
$$
TRIGGERS, UPDATABLE- MAT-VIEWS
Triggers: Sicherstellen kompl. Kons.Bedingungen, Auditing, Immer Db.Objekt und Tabelle zugeordnet, Stored Procedures, keine
Parameter, Auslösende Ereignise: INSERT, DELETE, UPDATE [ OF column]; Trigger Time: BEFORE, AFTER, INSEAD OF; Trigger
Restriction; Typen: Row-Trigger(FOR EACH ROW): pro betroffenes Tupel, Statement-Trigger: pro SQL-Anweisung; Implizite
Params(Row Tigger): OLD (UPDATE u DELETE)oder .old, NEW oder .new(INSERT u UPDATE); Haben Rechte des Owners, Owner
benötigt CREATE TRIGGER
Beispiele:
CREATE OR REPLACE FUNCTION CheckInsertAng() RETURNS TRIGGER AS $CheckInsertAng$
BEGIN IF (TO_CHAR (sysdate,'DY') IN ('SAT', 'SUN')) THEN RAISE EXCEPTION 'Nur während Arbeitszeit erlaubt'; END IF; END;
$CheckInsertAng$ LANGUAGE plpgsql;
CREATE TRIGGER CheckInsertAng BEFORE INSERT OR UPDATE OR DELETE ON Angestellter
EXECUTE PROCEDURE CheckInsertAng();
CREATE OR REPLACE FUNCTION cascade_updates() RETURNS TRIGGER AS $cascade_updates$
BEGIN
IF OLD.AbtNr != NEW.AbtNr THEN
UPDATE Angestellter A SET A.AbtNr = NEW.AbtNr WHERE A.AbtNr = OLD.AbtNr;
END IF; END;
$cascade_updates$ LANGUAGE plpgsql;
CREATE TRIGGER cascade_updates AFTER UPDATE OF AbtNr ON Abteilung FOR EACH ROW
EXECUTE PROCEDURE cascade_updates();
CREATE OR REPLACE FUNCTION check_SalaerAenderung() RETURNS TRIGGER AS $check_SalaerAenderung$
BEGIN
RAISE EXCEPTION 'Salaer nicht um mehr als 10% ändern!';
END;
$check_SalaerAenderung$ LANGUAGE plpgsql;
CREATE TRIGGER check_SalaerAenderung BEFORE UPDATE OF Salaer ON Angestellter FOR EACH ROW
WHEN ((new.Salaer < old.Salaer * 1.1))
EXECUTE PROCEDURE check_SalaerAenderung();
CREATE OR REPLACE FUNCTION increment_salaer(v_salaer Firma.SalaerSumme%TYPE) RETURNS void AS $increment_salaer$
BEGIN UPDATE Firma SET SalaerSumme = (NVL(SalaerSumme, 0) + v_salaer) ; END;
$increment_salaer$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION berechne_SalaerSumme() RETURNS TRIGGER AS $berechne_SalaerSumme$
BEGIN IF DELETING THEN SELECT increment_salaer(-1 * old.salaer) ; ELSIF UPDATING THEN SELECT increment_salaer( new.Salaer old.Salaer ) ; END IF ; END ; $berechne_SalaerSumme$ LANGUAGE plpgsql;
CREATE TRIGGER berechne_SalaerSumme AFTER INSERT OR UPDATE OF Salaer OR DELETE ON Angestellter FOR EACH ROW EXECUTE
PROCEDURE berechne_SalaerSumme();
Ausführung von Triggers : 1) Alle BEFORE statement Triggers 2)Für jedes betroffene Tupel gilt : a)Führe alle BEFORE ROW b)
Bearbeite TUPEL (Lock und UPDATE) c) Führe alle AFTER statement Trigger aus 3) Überprüfe allfällige derred integrity constraints 4)
Führe alle AFTER aus
LOGON/LOGOFF-Trigger: Bei Oracle
CREATE, ALTER, DROP auf Trigger möglich
INSTEAD-OF Trigger: Bei update auf views, anstelle normalen sql, leiten Modifikation von auf views zur darunterliegender Tabelle,
Beispiel:
CREATE OR REPLACE VIEW AbtLeiterInfo(AbtNae, ALPersNr, ALName) AS
SELECT abt.name, ang.person, ang.name FROM Abteilung abt inner join abteilung aal on abt.abtnr = al.abtnr inner join angestellter
ang on ang.persnr = al.abtchef;
CREATE OR REPLACE FUNCTION AbtLeiterInfo_Insert() RETURNS TRIGGER AS $AbtLeiterInfo_Insert$
DECLARE rowcnt integer;
DECLARE abtnr integer := 1001;
BEGIN
SELECT COUNT(*) INTO rowcnt FROM Abteilung Abt WHERE Abt.name = NEW.AbtName;
IF rowcnt = 0 THEN select abtNr_SEQ.nextval INTO abtnr from dual; INSERT INTO Abteilung (abtnr, name) VALUES (abtnr,
NEW.AbtName);
ELSE SELECT Abt.abtnr INTO abtnr FROM abteilung Abt WHERE Abt.name = NEW.AbtName; END IF;
SELECT COUNT(*) INTO rowcnt FROM Angestellter WHERE persnr = NEW.ALpersnr;
IF rowcnt = 0 THEN INSERT INTO Angestellter (persnr, name, abtnr, salaer) VALUES (NEW.ALpersnr, NEW.ALName, abtnr, 10000);
ELSE UPDATE Angestellter SET Name = NEW.ALName WHERE persnr = NEW.alpersnr; END IF; END;
$AbtLeiterInfo_Insert$ LANGUAGE plpgsql;
CREATE TRIGGER AbtLeiterInfo_Insert INSTEAD OF INSERT ON AbtLeiterInfo FOR EACH ROW EXECUTE PROCEDURE
AbtLeiterInfo_Insert();
Updatable Views: Jede Kolonne view auf Kolonne einer einzigen Tabelle mappen, View darf nicht(SET,DISTINCT,aggregation, GROUP,
ORDER, MODEL, Collection Expression, SUBQUERY, JOINS), Wenn Join: Das DML-Statement Nur eine der darunterliegenden Tabellen
betreffen, Keine Indexe auf Views, aber sie greifen auf Indexe der Tabelle zu
In Postgres: Für Triggers zu erst procedure schreiben,
CREATE OR REPLACE FUNCTION update_abt_statistik() RETURNS TRIGGER AS $$
BEGIN
TRUNCATE TABLE AbtStatistik;
INSERT INTO AbtStatistik
SELECT a.AbtNr, a.Name, sum(b.Salaer), count(b.persnr)
FROM Abteilung a, Angestellter b
WHERE a.AbtNr = b.AbtNr
GROUP BY a.AbtNr, a.Name;
RETURN NULL;
END; $$ language plpgsql;
dann
CREATE TRIGGER log_update AFTER UPDATE ON accounts FOR EACH ROW WHEN (OLD.* IS DISTINCT FROM NEW.* ) EXECUTE
PROCEDURE log_account_update();
Materialized View: Definition: Zwischengespeicherte View; In Oracle können Views gespeichert werden. In PostgreSQL Mög.
Probleme: Updates in Mat View nicht übernommen; Lösung: Setzten des Zeitpunktes der Synchonisation
-Snapshot(nur am anfang geupdated)
-eager(update wenn Änderung an Tabelle(sofort))
-lazy(update wenn Transaction commited)
-...plus(user defined oder best. intervall update)
INDEXSTRUKTUREN
Datei Manager lokalisiert Seite desgesuchten Satzes und beauftragt Puffer-Manager, sie in den Hauptspeicher zut un, dieser meldet
wenn fertig
Heap: Collection von Data Pages(DP) : Physikalische Speicherung Date, Rows unsortiert, allgemein 8kB zu 64kB Extends, PageSplit
bei Überläufen, wenn kein Platz -> Row chaining. lists of unordered records, retrieval inefficient as searching has to be linear
Table Scan: Scanning aller Pages einer Tabelle: Starte bei erster, durch alle durch, extrahiere alle Rows die zur Query passen ->IOOptimierung durch Lesen ganzer Extends, ab Query mit 80% Ausbeute schneller als über Index
Index: Datenstruktur für eff. Zugriff, Overhead bei Daten Ops: (Durchsuchen(Scan), (Equality Search), (Range Search), Insert(Lesen
und schreiben mehrerer Seiten erforderlich, Löschung wie Insert))
Arten: B(+)-Bäume, Hash, Bitmap, Mehrdimensionale und mehrstufe Indexe
B-Bäume: Geeignet für Sekundärspeicher, Range- und EqualSearch; Varianten(B+: Daten separat nur in Blättern analog ISAM, RBaum:mehrdimensional) Idee: Knotengrösse=Seitengrösse, Verzweigungsart hängt ab, wie viele Eintröge auf einer Seite Platz haben,
durch ausbalancieren immer logarithmisch; B-Baum der Ordnung(m, l; m>3m l+1): (Vielwegsuchbaum von Grad k=m/2, Knoten
entspricht Seite, Knoten hat Suchschlüssel und Söhnezeiger, Wurzel ist Blatt oder hat mindestens 2 Söhne, Jeder innere Knoten
ausser Wurzel hat mindestens m/2 und höchstens m sortierte Söhne -> Mindestbelastung 50%, alle Blätter gleiche Höhe, h
höchstens = 1 + (logm/2(N/2)) und mindestens = logm(N)
Einfügen: Rekursive Suche nach Schlüssel, gibt Stelle, Schlüssel einfügen, Ist Knoten überfüllt teile: Lege neuen Knoten an und
belege ihn mit Schlüsseln, die rechts vom mittleren Eintrag des überfüllten Knoten, Füge mittleren Eintrag von überfüllt in Vater,
Verbinde Verweis rechts des neuen Eintrag im Vater mit neuen Knoten; Falls Vater überfüllt: Wenn Wurzel, neue Wurzel, sonst
wiederholen
Löschen: Wenn Anzahl der Schlüssel in einem Knoten null, zwei benachbarte Knoten zusammen, Liegt Schlüssel auf Blatt:
entfernen. Liegt Auf Knoten und m/2 wird unterschritten -> Unterlaut: Es muss ein Ersatz-Knoten vom Bruder vie Vater geholt
werden -> Falls Bruderknoten jetzt unterlaufen: Verschmelzen, Lösche leeren Knoten, Wenn Wurzel, Bestimme neue Wurzel, Falls
Vaterknoten unterlaufen: Wiederholung
B+ Baum: Datenelement nur in Blättern, Innere Knoten nur Zeiger, Zugriff immer zum Blattknoten, Blattknoten verkettet; Vorteile:
Höhere Fanout, da die Datenmenge in Knoten kleiner, Kleinere Tiefe, weniger IO’s. Vorherrschend in DBS
B+-Index: Diskbasierter B-Baum über einem Attribut, jeder Knoten enthält keine Non-Key Daten, Blatt-Knoten enthalten DiskReferenz auf das gespeicherte Tupel
Clustered B+ Index: Wie B+-Index, aber Blatt-Knoten enthalten die Tuples, dh Tupels sind sortiert nach dem Attribut des Index
Clustered Index: Blätter enthalten Data-Records in sortierter Reihenfolge, Oft für Primärschlüssel, Schneller Zugriff via
Primärschlüssel, Nützlich für Kolonnen, die häufig in geordneter Reihenfolge oder range searches; Jeder Table nur einen Clustered
Index, Da Rows physisch so gespeichert, etwa 5% Tablegrösse, vor allen anderen Indexes anlegen
Unclustered Index: Blätter enthalten Referenzen auf Records-> Wie Index in Büchern, Meist als B-Bäume, jede Page in einem Index
hat Page-Header, gefolgt von Indexrows. Jede Indexrow hat Schlüssel und Pointer zu anderen Page oder Data.row, Jede Page heisst
Indexknoten, Jede Page in Blättern oder Zwischenstufen hat einen Pointer zu den nächsten und vorherigen Knoten in doppelt
gelinkter Liste
Hash: Hash-Funktion h: Ordnet Keys zu Records zu, 0..n-1 konkrete Schlüssel zu Blöcken, NULL-Werte nicht zugelassen; Problem:
Overflows, Lösung: OverflowChains; Eigenschaften: EqualSearch, für optimierte Memory-Strukturen; Sehr gut für Punktqueries,
wenn keine Overflowchains, Gut für MultipunktQueries; Nicht gut für range, prefix oder External Queries-> Reorganisation bei
Overflowchaining
Bitmap: Ordnet Attributswerte als Bitmuster; Eigenschaften: Geeignet für Wertebereiche mit geringer Kardinalität, Schnelle Abfrage
vor allen AND/OR, Langsam bei Modifikationen; Einsatz in Datawarehouses
Indexe wählen, Erstellen: Kriterien(Welche Indexe hat DBS, Tabellengrösse, Oft Daten löschen/einfügen, Welche Attribute für
Queries, Wertebereiche); Index-Kandidaten sind Attribute(Die Schlüssel sind, An Joins teilnehmen, Sortierungen, Group by,
Gleichheits-oder Bereichs)
Indexe erstellen: Meist CREATE INDEX <indexName> ON <Table(attr)>; DROP INDEX <IndexName>; Unique Index : Automatisch bei
PK-Attribut oder Unique-Constraint, Manuell sonst. Non-Unique: Manuell erstellen für zb FK-Attr, Range oder Point-Queries; Indexe
über mehrere Attribute: evt Reihenfolge wichtig; Clustered-Index mit „included columns“->Wichtig fürindex-covering-queries
Kosten Modell: Ziel(Abschätzen Anzahl IO-Ops für Anfrage, Zeit für in-memory Berechnungen = 0)
Definitionen: (P= nr DataPages mit Füllfakter=67%, R=nr Records per Page, Für Tree Indexes: F=Fanout=Durchschn. nr Kinder in NonBlatt-Knoten, PI=nr Pages im Leaf-Level Index
Heap: Heap Scan(Table Scan) : Anzahl I/O = P; Search nach eindeutigen Attr: nr I/O = ½ * P
Abschätzung Nr Zugriffe Clustered Index: 20000 Blöcke zu 20 Records, Index mit 200 Einträgen F=200:
Scan: I/O=P; Eindeutige Suche mit Gleichheitsbedingung: Annahme: Lokalisierung erster Page mit Gleichheitsbedingung in logF(P),
Binary Search in Page liefert gesuchten Record: I/O = logF(P) F = nr Einträge Index
Suche mit RangeSelektoren: Annahme: Lokalisierung des ersten Records wie Gleichheit, Sequentielles Lesen der n sortierten
Records -> n / R Pages => I/O = logF(P) + Ceiling(n/R)
Abschätzung Nr Zugriffe Unclustered Index: 20000 Blöcke a 20 Records Index mit 200 Einträgen
Indexscan für sortierten Zugriff: Annahme: Grösse des IndexEintrags = 1/F Grösse der Records, NR Blätter = P * R /F, Anzahl DataEntries pro Index-Page = F, Anzahl DataEntries pro HeapPage =R, Anzahl DataEntries total = P*R, Verfahren: Scan Blätterlevel des
Indexes für jedes Data-Entry lies den Record vom Heap Kosten: I/O = P*R /F + P*R
Bemerkung: Evt schneller tablescan & sort
Suche mit Gleichheitsbedingung: Annahme: Lokalisierung erster Page via Index, Lokalisierung des Records mit in memory
binarysearch der geladenen Page, Lesen des Records mit einem Heap-Zugriff; I/O-Kosten: 1 + logF(P*R/F)
Suche mit RangeBedingung: Annahme: Lokalisierung erster Records wie in Gleichheits, Sequentielles Lesen des Indexes und Laden
des Records solange Suchbedingung erfüllt, N = Anzahl Tuples, weclche erfüllen, Anzahl I/O = logF(P/F) + n + n/F -> Wenn Suche mit
mehr als 10%Ausbeute -> Table scan mit Sort besser
Anzahl I/Os
Scan
Equality Search
Range
Abkürzung
Search
Heap
P
0.5*P
P
P=Anzahl Pages
PI=Anzahl Pages im Leaf-Level des Index
Clustered
PI=P
logF(PI)
logF(PI) +
F=Index Fan Out=Anzahl Records per
n/R
IndexPage
R=Anzahl Record per Page
unclustered
PI*R
logF(PI)
logF(PI) + n
n=Anzahl Tupels, die Suchbedingung
erfüllen
Query Processing
Query Engine Parst SQL und wandelt in Query Tree um-> Query Tree evt. Transformiert in äquivalenten Query Tree, Optimizer
generiert Ausführungspläne und wählt den optimalsten basierend auf Statistik über Datenverteilung, Zur Laufzeit werden
kompilierte Ausführungspläne mit den aktuellen Variablen gebunden und ausgeführt
Queries auf Tabelle bei Oracle (Oracle bei Ausführung eine folgender Operationen: Table Scan, Index Range Scan, Index Unique
Scan, Table Access bei Rowid, Sort(in memory odo filebased), Hash(in-memory oder file-based) Filterm View)
Arten Queries: PointQueries, MultipointQuery, RangeQuery, PrefixMatchQuery, ExtremalQuery, OrderingQuery, GroupingQuery,
JoinQuery
Joins
Klassischer Hash-Join: Mache kleinere in Memory-Hash-Table für kleinere Relationen :> Für jeden Record in einer grossen Relation,
durchsuche den hash-table->Geht gut wenn kleinere Relation in memory passt->Falls nicht passt, in kleinere Buckets unterteilen
Hash-Join mit Partitionierung: Partitioniere beide Relationen mit hash funktion h -> R Tupel in Partition i matchen nur S Tupel in
Partition i-> Lese eine Partition von R ein, hashe mit h2->Scan matching Partition von S, Suche nach Matches
Nested Loop Join: Optimierung durch Indexes
Block Nested-Loop-Join: Optimierte Variante des Nested-Loop-Joins, Jeder Block der äusseren Relation wird mit jedem block der
inneren Relation verglichen
Sort Merge Join: Sortiere R und S auf der Join-Kolonne, dann scanne sie um einen merge zu machen und gebe die Resultattuple aus
_> R wird einmal gescannt, jede S-gruppe wird einmal pro matchendes R-Tuple gescannt->wahrscheinlich im Tupel
Kostenmodell: Joins für den Join R|X| R.A = R.B |S|
Abkürzungen: N(R)=Anzahl Tupels R, N(S)=Anzahl Tuples S, P(R)=Anzahl Pages R, P(S)=Anzahl Pages S, S kleinere Relation, B = Anzahl
Hauptspeicherblöcke
Nested Loop (Block oriented): Jede Iteration liest B-2 Blöcke aus R und P(S) Blöcke von S -> Anzahl Iteration outer loop: P(R)/(B-2);
Kosten= Anzahl I/Os -> P(R) + P(S)*P(R)/(B-2)
Indexed Nested Loop (INL) I/O-Kosten: P(R) + c * P(R)*N(R), c: Kosten traversieren Index und Laden aller passenden Tupels s für ein
Tupel aus r
Hash Join I/O-Kosten: Partitionierung der beiden Relationen: 2*(P(R) + P(S)), Lesen Partitionen: P(R) + P(S); Total: 3*(P(R) +P(S))
Kann auf P(R) + P(S) reduziert werden, wenn gesammte erstellte Datenstruktur in Memory Platz hat, M >= P(S)
Merge Join I/O-Kosten: ExternalSort(R) + ExternalSort(S) + R + S -> R*log(R) + S*log(S) + R + S
Wahl JoinAlgo: Falls kein Index ->HashJoin. Falls Index, ist INL effizient wenn (Ein INL auf dem Index von S.B ist performanter als HK,
falls #unterschiedlicher Werte von S.B ungefähr #Rows von S-> Häufig, da meistens FKJoins, Unabhängig von # falls es ein Covering
Index, Falls S.B ein Clustered Index); Sonst kann HJ bessere Performance liefern
Index in folgenden Situationen nützlich: Nested Loop: non equi join ein index auf join attr kann fulltablescan verhindern, Einfügen
und löschen, FK constraint falls R.A Subset von S.B)
Indexe auf kleinen Tabellen: (Bei <200 Tuples häufig nicht, Grösse hängt von Grösse Indexkeys verglichen mit Tupelgrösse, Alle
Daten einer Tabelle sind in einer Page -> Table Scan schneller, Jedes Tuple belegt eine Page -> Index verbessert Performance
Anfragetuning/Optimierung
Typische Client-Server(Netzransfer grosser Daten, Ketten von FragenAntworten, PingPong) -> Lösungen(Eine komplexe Query
schneller als viele kleine, Abfragen als Views, Stored Procedures)
Phasen: Übersetzung(Transformation, finde geeignete interne Darstellung für Anfrage), logische Optimierung(Umformung des
Anfrageterms aufgrund Heuristiken), Physische Optimierung(Erzeugung eines oder mehreren Ausführungsplänen, in denen die a
bstrakte Algebraoperationen durch konkrete Algorithmen ersetzt)
Auswahl günstigsten Plans: Basierend auf statistischen Informationen aus dem Katalog Berechnung von Kostenvoranschlägen für
jeden möglichen Plan
Optimierung/Heuristiken, Teilziele: (Selektion so früh wie möglich, Verkleinerung Zwischenergebnisse, Basisoperationen als ein
Schritt ohne Zwischenspeicherung Zwischenresultate, Zusammenfassung gleicher Teilausdrücke-> Wiederverwendung
Zwischenergebnisse)
Logische, algebraische Optimierung: Basiert auf Termersetzung aufgrund Äquivalenzen, Auch regelbasierte Optimierung genannt
Physische Optimierung
(Einbezug von Indexes, Verbesserung Analyse mit Statistiken, Einsatz von Heuristiken und Kosten, Kostenbasierte
Optimierung(Generiere alle möglichen Pläne, bewerte Kosten, behalte billigsten), Analyse, Abschätzen Kosten(Für jeden Plan:
Kommunikationskosten(#Nachrichten, Menge übertragender Daten), Berechnungskosten(CPU, Pfadlängen),
IOKosten(Seitenzugriffe), Speicherungskosten(Temp Speicherbelegung im DBPuffer und Hintergrundspeichern))
Analyse Statistiken (Infos über Relationen und Indexe, Typischerweise im SysKatalog, periodisch aktualisiert, SysKatalog (data
Dictionary) enthält normalerweise(Kardinalität, Verteilungsinfos über attrs, Grösse: #Pages für jede Reli, Index Grösse: #Pages für
jeden Index, IndexHöhe: #Nicht-Blatt-Stufen für jeden Index, Sonstige Angaben zu Indizes)
Selektivität
Sind vers. Strategien anwendbar braucht es Kostenfunktion; Selektivität eines Suchprädikats schätzt # der qualifizierten Tupel relativ
zur Gesamt# der Tupel in Reli; Hohe Selektivität: tiefer Prozwert, QueryOptimizer bestimmt für optimalsten Planes die Selektivität
für CRUD; Erstelle Indexes auf Kolonnen(Die Häufig in Where oder Join, Deren Daten hohe Selektivtät aufweisen)
Abschätzen in Prozent (Lineare Interpolation): where a < 100 => (100/maxValueA) | where a > 100 => ((maxValueA100)/maxValueA) |
where a between 210 and 300 => (300-210)/maxValueA
für effektive Anzahl *AnzahlTupels rechnen
Dichte
Durchschnittliche prozentueller Anteil von Duplikaten(Falls tiefe Selektivität tief, Dichte hoch, Unique Index tiefe Dichte),
Dichterverteilung: (Uniform: Anzahl DistinctValues /#Tupels)
Selektivität und Optimizer
QueryOptimizer kann mit Histogramme die Selektivität bestimmen(tiefe Selektivität -> nimm Index; Hohe Selektivität -> Table Scan,
DBS bestimmt Histogramme basierend Stichprobe). Faustregel: Selektivität <= 0.1 DBMS verwendet Index, Selektivität >0.1 Dbms
macht Table Scan
Tipps zur Anfrageoptimierung
Join(Klausel-Syntax, Ans Ende der Anfrage), Attributswertebereiche(Numerische Vergleiche schneller als Text, Schnellere Vergleiche
am Anfang), Projektion(SELECT *) durch Angabe von Attributen ersetzen, SARG-able Queries verwenden, Wenn möglich
verwenden(DISTINCT, GROUPBY, HAVING, Unterabfrage durch JOIN, UNION durch WHERE ersetzen)
SARG-able Queries
Jede Query wird zuerst analysiert um Suchargumente zu finden -> Nur Suchargumente können Indexe benutzen, Ein Suchargument
ist entweder ein exakt Match oder eine Range, Suchargumente können Listen sein, die mit AND verknüpft sind, Eine Seite des
Vergleiches ist Konstante oder auflösbare Variable, Eine Seite des Vergleichs ist Kolonnenname
Best Practices Indexing
Bevor Indexes erstellt werden, ist gutes Verständnis wichtig(logisches physisches design, datencharakteristik, wie werden daten
verwenden), Wie Benutzer Daten zugreifen(Welche Queries werden ausgeführt, Wie oft), Nur Indexes erstellen, die verwendet
werden(Nur eingesetzt, wenn sie 90% der Tupel eliminieren, Attribute der Indexes kurz halten, keine langen Strings, Clustered
Indexes gut für Ranges und Sorting, NonClustered gut für pointQueries aber auch range oder order, Covering Index: enthält alle
Attribute für die Abfrage sehr schnell -> Abwägen zwischen Geschwindigkeit und Indexgrösse), Kandidaten für Indexes(PK und FK,
Attribut auf denen häufig range, Attribute die häufig in sortierter Reihenfolge, Attribute die häufig in Aggregationen gruppiert),
Attribute ohne Index(Selten in Queries vorkommen, Die wenig unterschiedliche Werte aufweisen, Alle BLOB-Typen)
DATENSTRUKTUREN:ARRAYS, DICTIONARIES, GRAPHS
Defi: Gruppierung von variablen Nummer von Datenitems; Implementierung von Collections(Listen, Sets, Bags, Trees oder Graphen,
enum kann Liste oder Set); Semantik:Linear Collection(Listen/Arrays, PrioQueues, Heaps), AssoCollections(Sets, Multisets,
AssoArrays), Graphen und Trees
Arrays: Collection mit fixer oder variabler Länge, keine Sets, jene modelliert man als seperate Tabelle, Postgresql: Basistyp, variable
Länge; Index started bei 1, Syntax:
CREATE TABLE sal_emp(name text, pay_quarterly integer[], schedule text[][]);
INSERT INTO sal_emp VALUES(‚Bill’, ARRAY[100, 1000], ARRAY[[‘hello’, ‘bye’], [‘lul’, ‘lal’]]) ; Direkt auswählen : SELECT ARRAY[1, 2,
3+5]->{1, 2, 8} ; Subslices : SELECT schedule[1 :2][1 :1] ( [von:bis] ) FROM sal_emp WHERE name =’Bill’ ; -> {{‘hello’}, {‘lui’}} ; SELECT
* FROM sal_emp WHERE 100 = ANY(pay_quarterly)//Wert irgendwo im array ;
Operationen auf Arrays : Ist x IN : <@ (SELECT ARRAY[2, 7] <@ ARRAY[1, 7, 2]; -> true);; Gleichheit: = (SELECT ARRAY[1.1, 2.1,
3.1]::int[] = ARRAY[1, 2, 3]; -> true);; Haben Elemente gemeinsam/überlappen:&& (SELECT ARRAY[1, 4, 3] && [2, 1]; -> true;
Concatinate/Verbinden: || SELECT ARRAY[1,2] || ARRAY[3,4]-> {1,2,3,4,});
Array functions: array_ndims(arr)=>nr of dimensions of array array_dims(arr)=>dimensionen des arrays als String),
array_append(arr, el), array_cat(arr1, arr2), array_lower(arr, int)-> untere Bound des Levels, array_upper(arr, int)->Obere Bound,
array_length(arr, intDim)-> Gibt länge als int, Select array_append((select b from aa where a = 1), 5); Select array_prepend(5, (select
b from aa where a = 2));, select array_to_string((select b from aa where a = 1), ';' == delimiter); select unnest((select b from aa
where a = 1)); -> flattet den array, jedes element auf eigene zeile
Modellierung von Graphen mit PunktTable und Recursive Queries
CREATE TABLE graph(id serial, node1 int, node2 int);
WITH RECURSIVE graph_cte(node1, node2) AS (SELECT node1, node2 from graph
UNION ALL SELECT node2 AS "node1", node1 AS "node2" FROM graph),
paths(node1, node2, path) AS(SELECT node1, node2, ARRAY[node1] AS "path"
FROM graph_cte b1 WHERE b1.node1 = 2 --Start Node
UNION ALL
SELECT b2.node1, b2.node2, p.path || b2.node1 FROM graph_cte b2
JOIN paths p ON (p.node2 = b2.node1 AND
b2.node1 <> ALL (p.path[2:array_upper(p.path, 1)]) ))
SELECT path || node2 AS "path" FROM paths WHERE node2 = 6 --Ende node
ORDER BY array_length(path, 1), path;
Alle Untergebenen des Angestellten 1010, auch die Untergebenen der Untergebenen
with recursive leafs(idchef) as (values(1010) union all select persnr from angestellter a, leafs l where a.chef = l.idchef) select persnr
from angestellter a, leafs l where a.persnr = l.idchef;
Dictionaries oder AssoArrays: Paare von Schlüssel-Werte Paare: Implementiert beides als String, Keys eindeutig sein
Modellierung:
CREATE TABLE kvptable (id serial PRIMARY KEY, eventid int NOT NULL, key text NOT NULL, value text);
INSERT INTO kvptable (eventid,key,value) VALUES (1,'Medication Name','Ibuprofen'), (2,'Medication Name', 'Curcumin'),
(1,'Route','Oral: Capsule'), (2,'Route','Intravenous: Liquid'), (1,'Dosage','50mg'), (2,'Dosage','100mg');
BeispielQueries Dictionaries modelliert :
SELECT eventid, key, value FROM kvptable WHERE key = 'Medication Name' AND value = 'Ibuprofen'
Find a list of eventid's for which our medication matches:
1. Variante : SELECT eventid FROM kvptable WHERE key = 'Route' AND value = 'Oral: Capsule' AND eventid IN (
SELECT eventid FROM kvptable WHERE key = 'Dosage' AND value = '50mg' AND eventid IN (SELECT eventid FROM kvptable WHERE
key = 'Medication Name' AND value = 'Ibuprofen' ));
2. Variante : SELECT k1.eventid FROM kvptable k1 INNER JOIN kvptable k2 ON k1.eventid = k2.eventid INNER JOIN kvptable k3 ON
k2.eventid = k2.eventid WHERE k1.key = 'Route' AND k1.value = 'Oral: Capsule' AND k2.key = 'Dosage' AND k2.value = '50mg' AND
k3.key = 'Medication Name' AND k3.value = 'Ibuprofen';
Implementation mit hstore:
CREATE EXTENSION hstore; CREATE TABLE hstoretable ( id serial PRIMARY KEY, eventid int NOT NULL, kvp hstore NOT NULL);
INSERT INTO hstoretable (eventid,kvp) VALUES (1,hstore('Medication Name','Ibuprofen') || hstore('Route','Oral: Capsule') ||
hstore('Dosage','50mg')), (2,hstore('Medication Name','Curcumin') || hstore('Route','Intravenous: Liquid') ||
hstore('Dosage','100mg'));
BeispielQueries Dictionaries mit hstore :
SELECT eventid, kvp FROM hstoretable WHERE kvp @> hstore('Medication Name','Ibuprofen');
SELECT eventid, kvp FROM hstoretable WHERE kvp @> hstore('Medication Name','Ibuprofen') AND kvp @> hstore('Route','Oral:
Capsule') AND kvp @> hstore('Dosage','50mg');
Implementation in postgres mit hstore():
CREATE TABLE test (col1 integer, col2 text, col3 text); INSERT INTO test VALUES (123, 'foo', 'bar');
SELECT hstore(t) FROM test AS t;
List all keys : SELECT akeys(mykvpfield) FROM.. –Get all key-value-pairs: SELECT each(mykvpfield) FROM… --Get Key Value SELECT
mykvpfield ->’name’ FROM… --Test if key exists : ..WHERE mykvpfield ? ‘<value>’
Index für GIST/GIN : CREATE INDEX hidx ON testhstore USING GIST(h) ;
select akeys(tags) from planet_osm_point Order By tags LIMIT 5;
select distinct akeys(tags) as keys from planet_osm_point Order By keys limit 10 ;
select distinct each(tags) as keys from planet_osm_point Order By keys limit 10 ;
select tags->'name' from planet_osm_point where osm_id = 11210062 or osm_id=50075375;
select * from planet_osm_point where tags?'parking';
SELECT hstore_to_array(tags) as "linear array" FROM planet_osm_point where osm_id in (11210062,50075375);
Datenstrukturen: Trees, Semistrukturierte Daten(XML, JSON)
Baumstrukturen: Typische Anfragen(Alle Kinderknoten, Vor-Nachgänger)
Trees: Azyklischer verbundener Graph, falls verbunden und hierarchisch ist es ein rooteter Tree, geordneter Tree: Ordnung Kinder
strikt definiert
Baum-Implementation RDBMS:
Generische, relationale Implementation: Adjazenzliste(Columns : ID, ParentID ; einfach; Schelle Knoten moves, inserts und deletes;
aufwendig zum Finden von: Level, ancestry & descendence paths; Nutze CTE um zu travers)
Nested-Set-Modell(Art von Modified Preorder Tree Traversal; Columns:Left, Right; Einfach: Level, ancestry, descendants; movesm
insers und deletes aufwendiger als Adja, Verlangt Ordnung, grosser Aufwand Ummodelung, Preorder durchlaufen, erster Besuch lft
nummerien, dann rgt)
Materialisier Pfad:(Root kriegt Pfad 1, alle andere Knoten Pfad des Vaters + Nummer innerhalb seiner Brüder, Nachfolger einfach,
ancestors schwierig aber effizient, Kinder: Ineffizient, Vater: Effizient)
Tree-Typ ‚Ltree‘ (label tree) in Postgres: Hierarchisch strukturierte Beschriftungen(labels), Indexierbar mit btree und GIST,
Suchfunktion wie Volltext, label:[A-Za-z0-9_], max 256 Bytes; label path: Sequenz von lables, separiert mit ‚.‘, max 65KB,
Beispiele(L1.L2, Top.Countries.Europe), Limitiert bei Tiefe, Nachfolger einfach, Vorfahren tricky Installation: CREATE EXTENSION
ltree; Operatoren:
Ist linkes Arg. Nachfolger von rechts?: SELECT 'Welt.Europa.Schweis.SG'::ltree <@ 'Welt.Europa.Schweiz'::ltree;
Kleinster gem. Vorgänger: SELECT lca('Welt.Europa.Schweiz'::ltree, 'Welt.Europa.Malta'::ltree);
Beispiel: Suche alle Nachkommen des Knoten mit Id 2; als: normale Query, mit lpath, left_n und right_n als nested set
with recursive tmp as ( select id, name from skills where id = 2 Union All select s.id, s.name from tmp Join skills s on s.parent_fk =
tmp.id) Select * from tmp where id != 2; with p as (select path from skills where id = 2)
Select u.id, u.name from skills u, p where u.path <@ p.path and u.id != 2;
select u.id, u.name from skills u where u.mpath @@ '2' and u.id != 2;
select u.id, u.name from skills u, (select * from skills where id = 2) as p where (u.left_n BETWEEN p.left_n AND p.right_n) AND
u.left_n != p.left_n;
XML-Funktionen:
XML aus Tabelle: table_to_xml(‚tblname‘, True, 'False', '');
XML aus Query: select query_to_xml('select s.vorname, l.name from students s inner join laptops l on l.personid = s.matnr', True,
'False', '');
-- # Fügen Sie einen neuen XML Record ein.
insert into studentsxml values('<blub>whatever</blub>');
-- # Führen Sie folgenden XPATH Abfragen durch:
-- ## Ausgabe aller =[studenten]=, vollständige Records
SELECT xpath('/students', c) FROM studentsxml;
-- ## Ausgabe des ersten =[studenten]=, vollständiger Record
SELECT xpath('/students/student[position()=1]', c) FROM studentsxml;
-- ## Ausgabe der Matrikelnummer =[matnr]= des ersten =[studenten]=
SELECT xpath('/students/student[position()=1]/matnr/text()', c) FROM studentsxml;
-- ## Ausgabe des Laptop Record mit lid=222
SELECT xpath('//laptop[@lid=222]', c) FROM studentsxml;
-- ## Ausgabe des =[vorname]= des Studenten mit zwei Laptops, ''Hinweis: verwenden sie das count() Prädikat''
SELECT xpath('//*[count(laptop)=2]/parent::student/vorname/text()', c) FROM studentsxml;
JSON:
CREATE TABLE rpg_items (c1 serial, data json);
INSERT INTO rpg_items (data) VALUES ('{"name":"sword","buy":"500","sell":"200","description":"basic sword","attack":"10"}');
INSERT INTO rpg_items (data) VALUES ('{"name":"shield","buy":"200","sell":"80","description":"basic shield","defense":"7"}');
INSERT INTO rpg_items (data) VALUES ('{"name":"shield","buy":"200","sell":"80","description":"basic shield","defense":[7,8,9]}');
INSERT INTO rpg_items (data) VALUES ('{"name":"shield","buy":"200","sell":"80","description": {"basic
shield":[1]},"defense":[7,8,9]}');
-- # Erstellen Sie eine oder mehrerere Tabellen mit Spalten von unterschiedlichen Typen inklusive Array-Typen
CREATE TABLE rpg_items_defense (c1 serial, buy int, sell int, description text, defense int);
CREATE TABLE rpg_items_attack(int serial, fields int[], description text);
INSERT INTO rpg_items_defense (buy, sell,description, defense) VALUES (200, 80, 'basic shield', 7);
INSERT INTO rpg_items_attack (fields, description) VALUES ('{500,200,10}','basic sword');
SELECT row_to_json(row(buy,sell,description,defense)) FROM rpg_items_defense;
SELECT row_to_json(row(array_to_json(fields), description)) FROM rpg_items_attack;
JSON Operationen:
json->int (get JSON array element)
‘[1,2,3]’::json->2
json->text (get JSON object field)
‘{“a”:1, “b”:2}’::json->’b’
json->>int (get JSON array element as text)
‘[1,2,3]’::json->>2
json->>text (get JSON object field as text)
‘{“a”:1, “b”:2}’::json->>’b’
json#>array of text (get JDON object at path)
‘{“a”:[1,2,3], “b”:[4,5,6]}’::json#>’{a,2}’
json#>>array of text (get JDON object at path as text)‘{“a”:[1,2,3], “b”:[4,5,6]}’::json#>>’{a,2}’
OBJEKTRELATIONALE DATENBANKSYSTEME
Schwächen RDBMS(Keine Koordinaten, keine Identität ausser Werte der Tupel, Keine Meth auf Datenstrukturen, keine
benutzerdefinierten Datentypen, Keine Referenzen, Keine Vererbung von Tabellen, Mengen-Ansatz versus Objekt
Objektrelationale Datenbanksysteme (ORDBMS): (Kompatibel mit best. DBs, evolutionärer Ansatz)
Paradigma:( Funktionale Erweiterung um OO, strukturelle Objektorientierung, Standard SQL:99, Eigenschaften( Benutzerdefinierte
ObjektTypen mit Vererbung und Methoden, Objekt-Tabellen und Vererbung, Packages, Objektidentität- und Referenzen,
Collections, ObjectViews
Postgres(Benutzerefinierte Objekttypen mit Vererbung, ohne Methoden, mit Operatoren; Objekt-Tabellen nur Tabellen, Multiple
Inheritance; Packages mittels Schema, OIDS aber keine Referenzen, mit Collections, ohne Object Views)
Oracle(Benutzerdefinierte ObjektTypen mit Vererbung und Methoden:Single Inheritance; Objekt-Tabellen und Vererbung, Packages,
OIDS und Referenzen, beschränkte Collections, keine ObjectViews)
Objekttypen: Abstract Data Type(ADT), User Defined Type(UDT), Definiert durch(Name des Typs, Attribute(Name, Typ), Methoden);
Verwendet für Definition von Objekttabellen, Definition von Attributen in relationalen oder in Objekttabellen
CREATE TYPE NameTyp AS (NStr varchar(20)); CREATE TYPE PersonenTyp AS (NName NameTyp, VName varchar(20));
Typen in relationalen Tabellen: Column Objects: Typen können auch für komplexe Attribute in relationalen Tabellen verwendet
werden, werden dann als ColumnObject bezeichnet; Postgres(OID fest eingebaut); Oracle(Tuples der relationen Tabellen haben
keine OIDS) Beispiele:
CREATE TABLE Angestellter (PersNr int PK, PersInfo PersonenTyp);
INSERT INTO Angestellter VALUES(100, PersonenTyp(‚Graf‘, ‚Michael‘));
SELECT persnr, (persinfo).nname from Angestellter; (Zugriff auf objektwertige Attribute mit ‚Punkt‘-Operator)
SELECT * FROM Person WHERE persinfo = PersonenTyp(‚Graf‘, ‚Michael‘));
Order By und VergleichsOperatoren auf benutzerdefinierten Typen nicht definiert!
Tabellenvererbung PostgreSQL: Mehrfachvererbung mit INHERITS, Constraints werden nicht geerbt -> z.B. Primary Keys!
CREATE TABLE a (id int PRIMARY); CREATE TABLE a1 (remarks text) INHERITS(a); CREATE TABLE a2 (fkey int references a) INHERITS(a);
CREATE TABLE b (remarks text) INHERITS(a1,a2);
SELECT * from a; // Selektiert auch Tupel von a1 und a2 und b!
-> Liskovsches Substitutionsprinzip: ein Programm, das Objekte einer Basisklasse T verwendet, funktioniert auch mit Objekten der
davon abgeleiteten Klasse S, ohne dabei das Programm zu verändern, Primary Key Constraint wirkt nur auf Tabelle A, durch
einfügen in a1,a2 und b können ids mehrfach vorkommen obschon id PK ist.
"TRUNCATE a CASCADE;" alle Tabellen leeren, "DROP TABLE a CASCADE;" alle Tabellen löschen (wegen der Vererbung).
Objekttabellen:
Sind Instanzen von Objekttypen, Bei Deklaration können Defaults und Constraints angegeben werden; Jedes Tupel(RowObject) hat
OID
Object Identifiers (OIDs) Jedes Row-Object wird mit einem systemgenerierten 16 byte-OID systemweit eindeutig identifiziert
Aggregations-Datenmodelle: Umfassen: Arrays, Dictionaries, geschachtelte Strukturen, Collection von related objects die wir als Unit
behandeln wollen => Unit(für Daten-Manipulationi, Konsistent, Speicherung)
BASE: Basically Availability -> immer erreichbar, Soft State -> Konsistenz ist kein fester Zustand, Eventual Consistency ->Daten sind
MANCHMAL Konsistent
Konsistenz: Kann erhöht werden durch mehr Knoten -> zum Preis einer erhöhten Latenz
CAP Theorem (Kompromiss zwischen 2 Eigenschaften muss getroffen werden): Consistency -> Daten sind gleich, bei jeder Replikation
auf jedem Server, Availability -> Daten müssen immer verfügbar sein Partition Tolerance -> DB läuft trotz Netzwerk- und Maschinen
Ausfälle
NoSQLKategorien(Key/Value, Dokument, Column-Familiy-Stores, Graph, OODBMS, XML)
Key/Value-Datenbanken -> Aggregations Orientiert, haben Metadaten, Value ist opak für DB,
Dokumenten-Datenbanken -> Auch Aggregations Orientiert, Value ist strukturiertes Dokument: JSON oder BSON z.B MongoDB
Dokument-Begriffe: DB/Schema -> Instanz/DB, Table -> Collection, Row -> Document, rowid -> _id, Join -> DBRef
Column-Family Stores: Jeder Key verknüpft mit mehreren Attributen (Columns -> Google BigTable
Graph- und schemalose DBS: Beziehungen sind wichtig -> Nodes (Person) und Beziehungen (mag, besitzt, hat Adresse, …)
DBS-> nichtuniforme Daten oder implizites Schema
Verteilte Datenbank Modelle
Arten des Verteilens(Sharding(horizontales Partitionieren/skalieren), Replikation), Replikation(Master-Slave, Master-Master)
Konsistenz kann in verteilten DBs durch mehr Knoten erhöht werden, zum Preis höhere Latenz; Durability zum Teil zu Gunsten
Performance opfern; Quorem: Konsistenz oder Durability opfern durch Mindestanzahl
Map Reduce: Materialisierte Views sind gespeichertes MapReduce-inkrementell aktualisiert, Parallele (Aggregierungs)-Anfragen
einfacher und scheller, können nichts mehr wie UDFs, Schreiben meist auf Disk
MongoDB:(BSON, MasterSlave, Sharding, C++, Query:(<db>.<collection>.find({„<JSONobject>“:<value>})
CREATE: DB: use <DBname>, Collecton: <DBname>.createCollection(<name>, options); kann nun mit db angesprochen werden
db.unicorns.insert(„{name“:‘Aurora‘,“ gender“:‘f‘,“ weight“:450);
READ: db.<collection.find({"<JSONobject":<value>})
d = db.unicorns.find: d({name:'Aurora'}); d({gender:'f',loves:'apple'});d( {gender: 'f',loves:{ $all:['apple' ,'carrot']}});
d({gender:'f',$and:[{loves:'apple'},{loves:'carrot'}]}); d({gender:'f',loves:{ $in:['apple','carrot']}})
d({gender:'f',$or:[{loves:'apple'}, {loves:'carrot'}]}); d({gender:'f',vampires: {$exists:0}}); d({gender:'m', $and:
[{weight:{$gte:600}},{weight:{$lte:900}}]})—zwischen; Operatioren:($ne Not equal to;$lt Less than;$lte Less than or equal to;$gt
Greater than;$gte Greater than or equal to;$exists Check for the existence of a field;$all Match all elements in an array;$in Match
any elements in an array;$nin Does not match any elements in an array; $elemMatch Match all fields in an array of nested
documents;$or or;$nor Not or;$size Match array of given size; $mod Modulus;$type Match if field is a given datatype;$not Negate
the given operator check;
d({gender:'f',$or:[{loves:'apple'}, {loves:'carrot'}]},{_id:0})—Unterdrückt _id, sonst 1
UPDATE: mit $set, sonst ganzer Record ersetzt d.update({name: 'Roooooodles'}, {$set: {weight: 590}})
d.update({name: 'Aurora'}, {$push: {loves: 'sugar'}})
DELETE: db.unicorns.remove({name: 'Aurora'})
JOINS: d.findOne({_id: db.employees.findOne({name:'Moneo'}).manager})
RECOVERY
Konsistenzbedingungen: Regeln, denen die Daten genügen müssen, Transaktion: konsistenzerhaltende Operation.
Fehlerklassen
Lokale Fehler einer Transaktion:
Ursachen: Fehler in der Applikations-Software, Abbruch einer Transaktion - Auftreten häufig

Inkonsistenz: Festgeschriebene Änderungen der abgebrochenen Transaktionen

Recovery: Rollback oder 'lokales undo', Zeit für Recovery kurz (innert Millisekunden)

Fehler mit Hauptspeicherverlust:
Ursachen: Fehler in der DB-System-Software, Hardwarefehler, Stromausfall - Auftreten relativ selten

Inkonsistenz: Verlust von Änderungen, die noch nicht auf die Disk zurückgeschrieben wurden

Recovery: Recovery via Log Files REDO (abgeschlossene Trx wiederholen), UNDO (aktive/offene Trx zurücksetzen), Zeit für

Recovery mittel (innert Minuten)
Fehler mit Hintergrundspeicherverlust (Medien- oder Externspeicher)
Ursachen: Hardwarefehler im Disk-Treiber, Headcrash, Naturgewalten, Hacker/Viren - Auftreten sehr selten (verheerende

Wirkung)
Inkonsistenz: Auf der Disk gespeicherte Daten unbrauchbar

Recovery: Recovery via Full Backup + Logs, Logs sollten sich auf separatem Medium befinden, Zeit für Recovery sehr lang

(mehrere Stunden)
LogFile-Techniken
WAL-Prinzip: Write-Ahead Logging, vor commit alle Log-Einträge schreiben (für REDO im Fehlerfall), vor write (Disk) alle Log-Einträge
schreiben (für UNDO im Fehlerfall)
Checkpoints: Log-File bei vielen Trx. sehr gross, nur Analyse ab letztem Checkpoint nötig, Häufige Checkpoints:Schlechtere Perf. &
kürzere Recovery-Dauer, REDO Trx. (Winner), UNDO Trx. (Loser)
Backup:
Backup-Arten
Logischer Backup: + Flexibel, - Langsam (bei PG single threaded), * Export/SQL, * z.B. pg_dump, pg_restore
Physischer Backup:
Online: + Konsistent, - Bei 24/7 Betrieb inakzeptabel, * Keine Trx./Writes während Backup, * z.B. DB-Files kopieren,

Offline: - Inkonsistent, - Recovery aufwändiger, + Trx. während Backup erlaubt, * z.B. pg_basebackup

Inkrementelles Backup:
volle Sicherung zeitaufwendig -> Sichern der veränderten Datenbankseiten (= inkrementelles Backup)
Wiederherstellung: letzte Full Backup und alle danach erstellten inkrementellen Backups eingespielen anschliessend nur LogDateien nach letztem inkrementellen Backup
Point-In-Time-Recovery (PITR): Wiederherstellung der DB auf einen definierten Zeitpunkt
Backup Planung
Was? (welche Daten) - Wie lange zurück? – Wie? (Methode, Medium) – Maximale Ausfallzeit? – Recovery Tests!
PostrgeSQL
Logisches Backup: Pg_dump und pg_restore (psql), custorm format, immer ganze db wenn möglich, kann komprimieren, ev.mit split
aufteilen,
Physischer Backup: Offline Backup( Dateien kopieren, geht nur für identische versionen, inkrementell schwierig), Online Backup,
PITR(Base Backup mit pg_basebackup, WAL Log Archiving => PITR, Replikation, PITR kombinieren physisches Backup und WAL,
braucht weniger Speicherplatz als FullBackup, Warm Standby)
VERTEILTE DATENBANKSYSTEME(VDBMS)
Definition: kooperierenden DBMS, verteilt auf verschiedenen Computern (Knoten, Site) eines Netzwerks, jeder Knoten hat eine
autonome Verarbeitungsfunktionalität: kann lokale Applikationen ausführen, jeder Knoten partizipiert an globalen Applikationen,
welche Datenzugriff auf die verschiedenen Knoten benötigen
Anforderungen: Datenverteilungs- Transparenz(Benutzer sollen Queries formulieren können ohne auf die konkrete Verteilung der
Daten zu achten), Atomarität von verteilten Transaktionen(Benutzer sollen Transaktionen schreiben, die auf Daten in den
einzelnen Knoten zugreifen ohne sich um die Verteilung zu kümmern. Alle Änderungen auf den einzelnen Knoten sollen entweder
commited oder aborted werden)
Homogene VDBMS
 Gleiche Software auf allen Knoten  Alle Nodes kennen sich untereinander  Ein System gegenüber Client (transparent)  Gleich
wie zentral. DBMS nur das Daten fragmentiert/repliziert werden
Heterogenes VDBMS
Knoten mit unterschiedlicher Software - Problem: Verteilung der Transaktionen  Nodes mit unterschiedlichen Schemas Problem: Ausführung von Queries  Nodes kennen sich ev. Nicht – Problem: beschränkte Funtionalität für Kooperation  weitere
Probleme: - Unterschiedliche Protokolle - Unterschiedliche Datenmodelle
Verteilte Datenhaltung
Fragmentierung (Teile Relation r in Fragmente auf, die genug Information für Rekonstruktion haben)  Horizontal(shardening) Tupel auf separate Nodes verteilt  Vertikal - Einzelne Attribute auf sep. Nodes - Gemeinsame Schlüsselspalte nötig
Transparenz
Benutzer sieht globale Sicht, kennt die Replikation der Fragmente nicht
Queries werden auf der Relation definiert, nicht auf
den Fragmenten
Replikation
Redundante Speicherung auf Nodes  Vorteile:
Verfügbarkeit, Parallelität, Reduzierter
Datentransfer  Nachteile: Teure Updates (Propag.
auf Nodes), Komplexe Synchronsation, Evt.
Inkonsistente Zustände
Verteilte Transaktionen
Transaktion auf einer Datenbank ist immer lokal zu
einer Session, mehrere verteilte RM
Two Phase Commit (2PC)
2PC-Protokoll sichert Atomarität von verteilten
Transaktionen
Komponenten: Transaction Manager (koordiniert
Transaktionen über mehrere Resource Managers), Resource Manager ((z.B. DBMS, Message Queue System) unterstützt lokale
Transaktionen), Applikation (steuert Transaktionen)

Phase 1: "prepare to commit“ - Alle Anfragen ob Trx. machbar wäre - Alle „Ready“ goto Phase 2

Phase 2: "commit Sind alle Ready: commit - Ein einziger Fehler: abort, alle rollback
OBJEKTORIENTIERTE OODBMS
Anwendung(Audio/Video, Umweltdaten, 3DModelle, Spez in wissenschaft, software engeniering)
DBS kennt mehr Semantik:(Bessere Konsistenz Daten, Zugriff auf Daten schneller, da ganzes Objekt als Einheit laden oder
speichern, Manipulieren der Daten wird einfacher)
-Eher komplexe Daten und keine Anfragen; Klassen und Typen mit Extensionen, Projektion kann neue Typen generieren
Architektur: 2-tier C/S: Fat Client:(Applikationscode, DBCode(Impl. Persistenten Klassen, Queries), DBServer(Datenspeicherung, Locking)
OODBMS-Manifesto:Complex Objects, Object Identity,
Encapsulation, Types and Classes, Type and Class
Hierarchies, Overriding Overloading and late binding,
Computational completeness, Extensibility, Persistence,
Efficiency, Concurrency, Reliability, Declarative query
Language
Warum nicht POJOS serialisieren(Nicht vollständig( keine
Klassendef, Probleme mit Schemaevo), Nicht
orthogonal(Serialisierbare Klasse müssen Interface), Nicht
Persistenz(Object Identity geht verloren), Nicht
skalierbar(Objekt-Graph als ganzes serialisiert), Keine Transaktionen,Nicht concurrent)
Persistenz Strategien(Orthogonale Persistenz, Persi Strat(By Reachability, by Instantiating, By Inheritance)
Persistence By Reachability(Root object über namen gebindet, Alle Objekte über Referenz auch persistent, Laden von DB
automatisch beim navigieren, Alle DB-OPS über Transaktion)
2 Architekturen: PageServer und ObjectServer, bei ersterem erhält Client nur Page
OID systemweit eindeutig, auch nach löschen, Pointer Swizzling(Konversion von logischen Referenzen zu direkten Pointer
Referenzen, Typisches Problem beim Deserialisieren)
Es gibt logische OIDs(Nichts mir Speicherort, Umsetzungstabelle) und physische OIDs(Wiederverwendung nicht ausgschlossen nach
DBReorganistation, Verschiebung teuer, aber sonst schneller)
Gründe gegen: (Vielfach einfacheres Niveau als SQL, Mangel an komm. Datentypen wie Date, schlechte I18n, Kaum Objectview,
wenig Tools, wenig Interoperabilität, Einführungsaufwand, Fehlende Drittprodukte)
DB4O
(Kein O/R-Mapper, Keine Anpassung an Klassen, Eine Zeile um zu speichern, Local und Client-Server, ACID-Transactions,
ObjectCaching, Garbagecol, Verwaltung und Versionierung Schema, Java & .Net, kleiner Memory)
Local“embedded“(Standalone db, 1, Prozess oder Thread aufs Mal), ClientServerMode(TCP/IP zum Server, Methode
Db4o.openServer(fname, port), openClient(host, port, user, pass), „Embedded Mode“:(Kein Netzwerk, Port 0)
Object Container (representiert dbfo-db, verwaltet Transaktionen und Referenzen und Lebenszyklus)
ObjectContainer database = Db4o.openFile(„pub.db“);
Speicher: database.store(object)-Deep Copy, Persistence by Reachability
Abrufen: database.queryByExample(obj)-> genauer match// queryByExample(obj.Class) -> Alle von Klasse
Nativ: ObjectSet<Publication> pubs = database.query(new Predicate<Publication>() { public boolean match (Publication pub) {
return pub.getYear()> 2001;}});
Auch SOAD-Zugriffe möglich: Query query = db.query(); query.constrain(obj.class); query.descend(attr ).constrain(
Integer.valueOf(2001)),greater(); query.execute();
Update: Objekt holen, Attribute ändern und wieder storen, tiefe 1, nur basistypen und Strings, Sonsts cascadeOnDelete()
Löschen: Objekt holen, dann database.delete(obj); kaskadiert default nicht, sonsts
Db4o.configure().objectClass(Author.class).cascadeOnDelete(true);
Constraints nicht direkt unterstützt: Jede Klasse kann aber die Methoden objectOnDelete(), objectOnUpdate(), objectCanDelete()
und objectCanUpdate(), die jeweils entsprechend aufgerufen werden
Indexe mit Annotation @Indexed
NoSQL Charakterisierung Kategorien MongoDB-CRUD-Beispiele
Anforderung Web2.0: Grosse Datenmengen, Schreibzugriffe in verteilten Datenbanken, Hochverfügbarkeit
RDBMS: Single Point Failure, Kennen Scaling up, nicht Scaling out, einfache Parallelisierung
Definition: Nicht-Relational, Schemafrei, Archi auf BASE -> verzicht auf ACID!!!, Einfache Datenrepli, Einfaches API, keine Querynorm
für NoSQL
Neu: Verteilt, OpenSource, horizontal skalierbar, Applikationsdatenbanken, teil eines einzelnen Projekts, Webservice
Transaktionsmanager
Stellt sicher, dass alle RM’s entweder mit Commit oder Rollback abschliessen Ausserdem muss mit allen Fehlersituationen umgehen
können, die durch das Kommunikationssystem verursacht werden
Fehlersituationen
Absturz des Transaktionsmanagers
Absturz vor COMMIT gesendet -> Rückgängigmachen der Transaktion durch Versenden einer ABORT-Nachricht
Absturz nachdem RM ein READY mitgeteilt haben -> Blockierung der RM, (Absturz des Koordinators-> Verfügbarkeit des RM bez.
Anderer Transaktionen drastisch eingeschränkt)
Absturz eines Resource-Managers
Antwortet RM nicht innerhalb Timeout-Intervalls nicht auf die PREPARE-Nachricht -> RM abgestürzt; Koordinator schickt ABORTNachricht an alle Agenten, Abgestürzter Agent schaut beim Wiederanlauf in seine Log-Datei:
Kein READY-Eintrag bezüglich Transaktion T -> RM führt abort durch, Failed to Koordinator
READY-Eintrag aber kein commit-Eintrag -> RM fragt TM, was aus Transaktion T geworden ist; TM teilt COMMIT oder ABORT mit ->
RM macht je nach dem REDO oder UNDO
COMMIT-Eintrag vorhanden -> RM weiss, dass ein (lokales) REDO der Transaktion nötig ist
Nachricht verloren
PREPARE-Nachricht des TM an einen RM geht verloren oder READY-(oder FAILED-)Nachricht eines RM geht verloren -> Nach
Timeout-Intervall TM geht TM davon aus, dass betreffender RM nicht funktionsfähig ->t ABORT-Nachricht an alle RM (Transaktion
gescheitert), RM erhält im Zustand READY keine Nachricht zum Koordinator -> Rm ist blockiert, bis COMMIT- oder ABORT-Nachricht
vom TM kommt
X / Open XA (DTM)
Standardisiert Schnittstellen zwischen Komponenten in verteilten Systemen
Synchronisation in VDBMS
Serialisierbarkeit
Lokale Serialisierbarkeit an jeder der an den Transaktion
beteiligten Stationen reicht nicht aus -> deshalb muss man
bei der Mehrbenutzersynchronisation auf globaler
Serialisierbarkeit bestehen
Beispiel: Lokal serialisierbare Historie, Global nicht
serialisierbar
Zwei-Phasen-Sperrprotokoll in VDBMS
2PL wird auf verteilte Systeme adaptiert(Locken der Objekte,
Lesen / Modifizieren, Freigabe der Locks)
Jeder Knoten partizipiert in der Ausführung des Commit-Protokolls um globale Serialisierbarkeit zu gewähren
Globaler Lock-Manager
VDBMS unterhält einen globalen Lockmanager, Wenn Transaktion T was sperren will -> Anfrage an globalen Lockmanager.
Entscheidung: ja: Lockmanager Meldung an anfragenden Knoten, nein: Anfrage verzögern bis Lock gewährt werden kann;
Vorteil: Deadlock-Erkennung wie im Ein-Rechner-Fall

Nachteile: Jede Sperranforderung einer Transaktion verursacht eine Nachricht, Transaktion muss synchron darauf warten ->

schlechter Durchsatz und Antwortzeit; Zentraler Knoten ist Engpass für Leistung und Verfügbarkeit ("single point of failure");
Keine Knotenautonomie
Lokaler Lock Manager
Der verteilte Algorithmus greift auf die lokalen Lock-Manager auf den
einzelnen Knoten zu, Der lokale Lock-Manager kontrolliert den Zugriff
auf die lokalen Data-Items. Locks werden im Rahmen des 2PCProtokolls allokiert und freigegeben;
Vorteile: Arbeit ist verteilt; robuster gegen Ausfälle

Nachteile: Deadlock-Detektion schwierig; Performance kann

stark beeinträchtigt werden
Zeitstempel basierte Synchronisation
Jede Transaktion bekommt einen global eindeutigen Zeitstempel
Hauptproblem: Generierung einer global eindeutigen Zeit(lokal eindeutigen Zeitstempel + anhängen Rechner-Id
Konfliktoperationen verschiedener Transaktionen müssen stets in der Reihenfolge der Transaktionszeitmarken erfolgen;
Bedingungen verletzt -> betroffene Transaktion zurückgesetzt und mit neuen Zeitstempel wiederholt; Überprüfung mit Schreib- und
Lese-Zeitstempeln an den Datenobjekten, (Write Time Stamp) WTS bez. der Lesezeitstempel (read time stamp) RTS entspricht
Transaktionszeitmarke derjenigen Transaktion, die das Objekt zuletzt geändert bez. gelesen hat,
wenn gilt:(Ts(T) < WTS(x)): Lesezugriff auf Objekt x nicht zulässig
Für Schreibzugriff muss gelten:(Ts (T) > Max(RTS(x), WTS(x),
Deadlocks in VDBMS
Verteilter Deadlock
Erkennung von Deadlocks
 Mit Timeout: - Nach Ablauf zurücksetzen/neu starten - Simpel - Zu lang: Ressourcen schlecht genutzt - Zu kurz: „Deadlocks“ wo
keine wären
 Zentralisiert - Nodes geben Infos zu waits weiter - Zyklus im Graphen = Deadlock - Hoher Aufwand / Messaging - PhantolDeadlocks (Fehlalarm) durch überholte Messages bei Info-Austausch Vermeidung
 Optimistisch: - Validierung nach Trx. Abschluss
 Timestamp-basierend - Entscheidung ob Trx. Serialisierbar
Distributed Query Processing
Verteilte Anfragen
Zentralisiertes System -> Kosten der Query bestimmt von der Anzahl Disk-I/O's
Verteiltes System -> Kosten der Query bestimmt von: -Anzahl Netzwerk I/O's; -Performance-Gewinn durch paralleles Abarbeiten auf
mehreren Knoten)
Beispiel:
SELECT AVG(s.age) FROM Sailer s WHERE s.rating > 3 AND s.rating < 7;
Horizontale Fragmentierung:Tupels mit rating < 5 in Zürich, Tupels mit rating >= 5 in Genf
Ausführung der Query: Führe die Query auf dem Knoten Zürich und Genf aus => Resultat auf dem aufrufenden Knoten
zusammenführen, Wenn die WHERE-Klausel S.rating > 6 hiesse, dann wäre nur der Knoten Genf beteiligt
Verteilte Queries
Vertikale Fragmentierung:Tupels mit tis, sid und rating in Zürich, Tupels mit tid, sname, age in Genf
Ausführung der Query: Relation über Tupel-Identifier tid durch Join rekonstruieren, Auswertung der Query)
Relation repliziert auf beiden Knoten, Ausführung der Query(Wahl des Knotens abhängig von lokalen und Transport-Kosten)
Einfache Joins
R ist in der Site N1, S in der Site N2 gespeichert, Für jede Anfrage vom Knoten Ni muss das System die Resultate auf Ni liefern
Query Processing Strategien
Einfache Strategien: Join wird auf einem Knoten ausgeführt(Ship Whole: Relation vollständig an den Join-Knoten
übertragen(Minimale Nachrichtenanzahl, hohes Datenvolumen); Fetch as needed: Für jedes Tupel der lokal vorliegenden Relation
wird der Wert des Join-Attributs an den anderen Rechner geschickt, welcher das passende Tupel überträgt; Hohe
Nachrichtenanzahl, eventuell tieferes Datenvolumen (bei hoher join-Selektivität)), Kostenabschätzung anhand der
Kommunikationsanteile(Nachrichtenanzahl (#Nachrichten), Übertragungsvolumen (Anzahl Attributwerte #AW))
Semi Join
Reduktion des Overhead des Fetch-As-Needed-Ansatzes, Übertrage sämtliche Verbungattributwerte der ersten Relation in einer
Nachricht an den Knoten der zweiten Relation übertragen, Daraufhin können alle Verbundpartner in einer Nachricht an den ersten
Knoten zurückgesendet werden, wo dann die Join-Bildung erfolgt
REPLIZIERTE DATENBANKSYSTEME
Theorie Konfiguration Synchronisationsprotokolle Merge Replikation Replikation in kommz. Systemen
PRO's: Verteilung der Daten -> High Avalability, Skalierbarkeit (Lastverteilung), Vorbeugung Datenverlust, Grundlage Clients im
Disconn. Mode
Anwendungen: Load-Balancing, Remote Servers, Real-Time OLAP, Hochverfügbarkeit (Warm Standby), Mobile Datenbanken)
Loadbalancing: High Performance Cluster, hochverfügbar skalierbar, Master-Master asynchron oder synchron, Sehr schnelle
Verbindungen)
Anwendungen distributed geographic data processing with high availability(Asynchroner Multi-Master (Peer-Peer), Verteilte
Standorte, (Mittel-)schnelle Verbindung mit relativ hoher Verfügbarkeit
Real Time OLAP: Online Analytics Processing)(Backup und Data Warehouse, Asynchronous Master-Slave, Schnelle / mittelschnelle
Verbindung, Räumlich zentralisiert oder verteilte Standorte
Warm Standby: Aynchronous / Synchronous Master-Slave, Schnelle, hochverfügbare Verbindung, Zentraler Standort (synchron) oder
geographisch verteilt (asynchron)
Mobile Datenbanken: Master-Master / Merge Replikation, Disconnected Clients, (auch) langsame Verbindungen mit tiefer
Bandbreite
Korrektheit: Schwache vs. strenge Konsistenz, Protokolle/Verfahren für replizierte Daten damit nur eine Kopie verändert wird, trotz
Partitionierung des Netzwerks
Starke Konsistenz (synchron): ACID -> 1-Kopien-Äquivalenz, alle Replikate wechselseitig konsistent, Replikation mit Write-All-ReadAny, 2-Phasen-Commit Protokoll, grosser Protokoll-Overhead, Verfügbarkeit/Fehlertoleranz reduziert, Vollständige
Replikationstransparenz: Jeder Zugriff liefert jüngsten transaktionskonsistenten Objektzustand
Schwache Konsistenz (asynchron): BASE -> Eventuell keine strikte Serialisierung von Änderungen, paralelle Änderung mit
nachträglicher Konfliktbehebung, Primäre Kopie der Daten, Replikas nicht allzeit identisch, Verfügbarkeit/Fehlertoleranz/Performanz
hoch
Skalierung: Vertikal => HW eines Systems
aufrüsten, Horizontal/Sharding => Data Set auf
mehrere Systeme verteilen
Master-Slave: Primäre Kopie auf Master, Updates
auf Master => Publisher, Updates auf (Read-Only)
Slaves propagiert => Subscriber
Multi-Master: Jeder Master kann Updates
durchführen, komplexe Sync notwendig,
Asynchrone Replikation, Konflikte durch
gleichzeitige Änderungen
Replikationsarten:
Synchron (eager)->
Master aktualisiert alle Replikas in einer 2 PC
Transaktion, Daten sind immer konsistent (ACID),
Verteiltes Locking kann zu Deadlocks und
Wartebedingungen führen, Verfügbarkeit
eingeschränkt durch Fehlersituationen (zum
Beispiel Knoten nicht verfügbar)
<-Asynchron (lazy) mit Versionsnummern
Änderungen am Master werden nach Abschluss
der Transaktion asynchron an die Replikas weitergeleitet, Synchronisation
entweder periodisch oder nach Commit, -> Replikas werden nicht zur
selben Zeit aktualisiert, -> Konflikte können auftreten (sogenannte
eventually consistent reads), Höhere Performance als bei synchroner
Replikation, Höhere Verfügbarkeit, da ein Ausfall eines Knotens nicht zum
Ausfall des gesamten Systems führt
Update Propagation:
Wie werden die Update-Operationen beim Master erkannt und
weitergeleitet?, Triggers: Bei jedem Update auf dem Master feuert ein
Trigger, der die Änderungen in eine "update propagation table" einträgt),
Log-Analyse: Das Log-File wird gesnifft und die Änderungen werden
daraus hergeleitet, In der Regel effizientere Methode
Synchronisationprotokolle für Multi-Master Konfigurationen
Read-One/Write-All Strategie (ROWA): Write => Synchrone Änderung aller
Replikate bei Abschluss der Transaktion -> Alle Replikate sind konsistent,
Bevorzugte Behandlung von Lesezugriffen(Lesen eines beliebigen
(lokalen) Replikas, Hohe Verfügbarkeit für Leser), Sehr hohe Kosten für
Änderungstransaktionen(Schreibsperren bei allen Rechnern anfordern, Propagierung der Änderungen im Rahmen des CommitProtokolls (2PC)), Verfügbarkeitsproblem: Änderungen von Verfügbarkeit aller kopienhaltenden Knoten abhängig(Sei P die mittlere
Wahrscheinlichkeit, dass ein Knoten verfügbar ist, Bei N Kopien beträgt die Wahrscheinlichkeit, dass geschrieben werden kann: P ^
N, Wahrscheinlichkeit, dass gelesen werden kann: 1 - (1 - P)^N, Variante: Zur Abschwächung des Verfügbarkeitsproblems wurde die
Write-All-Available-Variante vorgeschlagen, bei der nur die Replikate der verfügbaren Rechner gesperrt und aktualisiert werden
müssen. Für einen ausgefallenen Rechner werden die nicht vorgenommenen Modifikationen eigens protokolliert und nach
Wiedereinbringen des Rechners nachgefahren)
Majority Protocol: Lesen oder Schreiben eines Objektes verlangt Zugriff auf Mehrheit der Replikate, Jedes Replikat kann gleichzeitig
von mehreren Transaktionen gelesen, jedoch nur von einer Transaktion geändert werden, Änderungstransaktionen auf
Datenelement Q:(Die Mehrheit der Replikate muss von den lokalen Lockmanagern mit Sperren belegt werden, Schreiboperationen
werden auf allen gesperrten Replikaten ausgeführt -> Versionsnummer wird erhöht -> mindestens ein Replikat ist aktuell), Vor- und
Nachteile(Funktioniert auch bei Ausfall einiger Knoten, Funktioniert nicht bei 2 Knoten, Hoher Kommunikationsaufwand(2(n/2 + 1)
Messages für Lock-Requests, (n/2 + 1) Messages für Unlock-Requests), Potential für verteilten Deadlock auch bei nur einem
Datenobjekt q:(Zum Beispiel jede von 3 Transaktionen hält locks auf 1 / 3 der Replikate von Q)
Quorum Consensus: Verallgemeinerung der bisher vorgestellten Verfahren, Jede Kopie erhält bestimmte Anzahl von Stimmen
(votes), Protokoll:(Leser erfordert R Stimmen (Read-Quorum), Schreiben erfordert W Stimmen (Write-Quorum), R + W > V (=
Summe aller Stimmen)(- > Ein Objekt kann nicht zur gleichen Zeit gelesen und geändert werden , -> Jedes Lese-Quorum enthält
mindestens eine aktuelle Kopie), W > V / 2(-> Ein Objekt kann nicht gleichzeitig (auch bei Netzwerk-Partitionierung) von mehr als
einer Transaktion geändert werden
Beispiel: Objekt A sei an vier Rechner R1 bis R4 repliziert Stimmenverteilung <2, 1, 1, 1>, das heisst V = 5, Sei R = 3, W = 3, -> R1 nicht
beteiligt: drei Rechner, um einen Lese- oder Schreibzugriff abzuwickeln, -> R1 beteiligt: R1 und ein anderer Rechner für eine
Schreiboperation, Sei R = 2, W = 4 (Bevorzugung der Lesezugriffe, -> R1 beteiligt: R1 und zwei andere Rechner für Schreibzugriff,
Lesezugriffe lokal auf R1, -> R1 nicht beteiligt: Objekt nicht änderbar
Eigenschaften:Festlegung von V, R und W erlaubt Trade-Off zwischen Lese- und Schreibkosten sowie zwischen Leistung und
Verfügbarkeit, Majority-Protokoll Spezialfall: Eine Stimme pro Kopie, R und W einfache Mehrheit
Snapshot-Replikation: Bisherige Verfahren sehr aufwendig -> Synchronisation und Kommunikationskosten, Snapshot = Einfacheres
Verfahren mit schwächeren Konsistenzanforderungen, Snapshot = materialisierte View (verteilt), nur für Lesezugriffe, Aktualisierung
periodisch oder nach jeder Änderung in der Ursprungstabelle
Merge Replikation
Unsynchronisierte Änderung eines replizierten Objekts an mehreren Knoten (Multi-Master) mit asynchroner Propagierung der
Änderungen, Performance- und Verfügbarkeitsvorteile gegenüber synchroner Aktualisierung, Unabdingbar für mobile DB-Nutzung
(disconnected client) mit Änderungsbedarf (zum Beispiel Aussendiest-Mitarbeiter) (Eintragung neuer Kunder / Aufträge (geringe
Konfliktgefahr)), Probleme:(Nachträgliche Konflikt-Behandlung, Mischen paralleler Änderungen (Merge-Replikation))
Konflikte Merge Replikation
Konfliktmöglichkeiten für(Update, Insert (zum Beispiel Eindeutigkeit), Delete), Konflikterkennung( Objektänderungen enthaltenen
Zeitstempel v der Vorgängerversion und neuen Wert, Konflikt: falls lokaler Zeitstempel einer zu aktualisierenden Objektversion
abweicht von v, Konfliktwahrscheinlichkeit wächst mit Anzahl der änderbaren Replikate und Aktualisierungsverzögerung),
Anwendungsspezifische Konflikt-Behandlung (reconciliation)(Vordefinierte Strategien in externer DBS: "last timestamp wins", "site
priority", Benutzerdefinierte Konfliktauflösungsroutinen oder manuelle Konfliktbehebung, Gefahr von "lost updates" und anderen
Anomalien (keine Seralisierbarkeit))
Konflikte
Update conflicts: Bsp. 2 gleichzeitige Updates auf unterschiedlichen Replikas mit unterschiedlichen Werten => timestamp
vergleichen
Uniqueness conflicts: 2 Nodes wollen zu mir einen neuen Eintrag replizieren, beide haben den selben PK
Delete conflicts: Passiert, wenn zwei Transaktionen von verschiedenen Nodes passiert, bei der eine Transaktion ein Data-Record
löschen will und die andere sie updaten oder löschen wll Ordering conflicts: kein Beispiel
Konflikte können automatisch durch vordefinierte Strategien oder durch applikationsspezifische (programmierte) Regeln auflöst
werden)
MongoDB:Brücke zwischen key-value(schnell und skalierbar) und traditionellen RDBMS mit vielen Funktionen
Replika Sets: Normal 3 Nodes pro Set, 1 Primary Node wird gewählt, W nur an Primary/immer nur 1 Primary, Daten werden nach W
repliziert, Load-Balancing für R
Automatic Failover: Verbindung wird durch Heartbeat überprüft, bei Ausfall des Primary wir ein neuer Primary bestimmt
Syncing: Oplog ist eine geordnete Liste aller W's, Nach W auf Primary wird die Primary Oplog nachgeführt, Secondaries kopieren die
Primary Oplog und führen die Änderungen asynchron nach
Majorities: Ein Primary bleibt nur, solange er eine Mehrheit der Members erreicht, Nur eine Mehrheit an Members kann einen
Primary wählen => sicherstellung dass nur ein Primary vorhanden ist, eine W gilt als safe, wenn sie an eine Mehrheit repliziert wurde
Write Concerns: Wert, welche für eine W Operation abgegeben werden kann, Errors ignored/Unacknowledged: fängt: Netzwerk
errors, Ack (default): Ack nach In-Memory Eingang auf Primary, fängt Netzwerk-, Duplicate Key- other Errors, Journaled: Ack nach
Eintrag ins Oplog, stellt sicher das W einen shutdown überlebt, Replica Ack: Ack nach Replizierung, OPTIONAL: Wert für Anzahl
Replizierungen
Read Preference: Definiert die Routen für R-Operationen, Primary (default): Alle R von Primary, wenn unerreichbar=> Error,
primaryPreferred: Falls Primary unerreichbar => Secondary, Secondary/secondaryPreferred: (vertauscht), Nearest: Automatisch
nächster Vorteile: Latenz verbessern, R throughput erhöhen, für Backup-Operationen, R während failover ermöglichen, Secondary
liefert zuverlässlichere Daten!!!
Sharding: Partitionierung (Unterteilung) einer DatenKollektion auf mehrere Systeme unter Einhaltung einer geordneten Form Query
Routers (mongos): Interface für Clients/Applikationen, Verarbeitet Anfragen von Clients/Apps, ein Sharded Cluster verfügt normal
über mehrere mongos => Load-Balancing, Config Servers: Speichern die Metadaten des Sharded Clusters, Enthalten Mapping
Clusterdaten  Shards, Query Router verwendet dies für Datenzugriff, Production sharded Clusters verfügen über genau 3 Config
Servers
Sharded Collection Balancing: Shard Keys => Chunks (Splitting/Balancing) => Shards,
Shard Key: z.B. Index-Feld, werden in Chunks aufgeteilt (Range oder Hashbasiert auf
Shard Key, Chunk:
Zusammenhängende
Range von Shard Keys
innerhalb eines Shards,
Splitting => Chunk der zu
gross wird wird
aufgeteilt, Shard:
Unterschied an Anzahl
Chunks zwischen Shards
zu gross => Chunks von
einem Shard auf
anderen migrieren
Herunterladen