Autor Thema: rdbms. ein paar Punkte  (Gelesen 1383 mal)

Marinero Atlántico

  • Gast
rdbms. ein paar Punkte
« am: 15.05.05 - 03:10:35 »
Hallo,

Gut. Das waren jetzt ein paar bischen speziellere Bemerkungen. Trotzdem sind die für mich ziemlich zentral. Es würde mich weiterbringen, wenn jemand was dazu sagen könnte. Wo ich Unsinn rede, Ergänzungen, etc.

ich bin mir nicht 100% sicher...
Mir sind bei verschiedenen RDBMSen ein paar Dinge aufgefallen:
1. Es gibt eigentlich 2 Arten der automatischen Primary Key Erzeugung.
Das folgende ist jetzt auch damit verbunden, dass ich den PrimKey - Wert eines neu in der Datenbank persistierten Tupels (=Datensatz) natürlich auch im Objekt haben will, dass die Werte des Datensatzes in der Anwendung hält und ggbfls cached.
Ein normaler Anwendungsfall ist ja:
1.Der User gibt Werte ein
2. Die Anwendung tut diese Werte in Properties eines Objekts
3. Die Anwendung bastalt aus diesen Properties einen SQL-insert Befehl
4. Die Tabelle ist so definiert, dass der Primary Key eine hochzählende Zahl ist, die automatisch gesetzt wird. Praktisch alle RDBMSe haben dafür heute ein proprietäres Feature und es ist eine gute Sache.
5. Diesen Primary Key benötige ich dann natürlich auch im Objekt (z.B. für spätere updates)

Probleme macht Punkt 5
Wie kommt das Objekt an den von der Datenbank automatisch generierten Key?
Falls der Tupel (Datensatz) einen natural key hat. D.h. ein Attribut (Spalte), für die im Datenbankschema ein Eindeutigkeits-Constraint definiert ist (z.B.
Code
CREATE UNIQUE INDEX "index_User_Name" ON Person (nameUSER);
). Kann ich natürlich direkt nach dem insert ein select mit Hilfe dieses eindeutigen Attributs machen.
Code
Pseudo-code: 
select id from Person where nameUser = myPersonObject.getName();
Aber vielleicht hat nicht jeder Tupel einen solchen natürlichen Key.
Praktisch alle RDBMSe besitzen nun proprietäre Funktionen, mit denen ich in solchen Situationen an den Primary Key komme. Und das ist wohl auch performanter als der oben beschriebene Select.
Bei DB2 scheint man leider an den Wert eines automatisch erzeugen Primary Keys nur über eine globale Funktion nach dem Insert zu kommen:
Code
identity_val_local()
Das ist wohl problematisch.

Die 2 Threads greifen auf die DB zu und es kommt zu diesem Fall.
Beide Threads führen diesen Pseudo code aus:
Code
transaction_start();
INSERT INTO Person (nameUser) Values (person.getName());
person.setId(identity_val_local());
transaction_end();
Nun der folgende Fall:
Code
thread a macht insert.
THREAD-SCHEDULER gibt Prozessorzeit an thread b  
thread b macht insert. 
thread b ruft identity_val_local() auf.  //-> Prim-Key Wert vom Datensatz von b (was ok ist)
THREAD-SCHEDULER gibt Prozessorzeit an thread a
thread a ruft identity_val_local() auf  //--> Prim-Key Wert vom Datensatz von b!!!
Selbst wenn der identity_val_local() Aufruf direkt hinter dem insert steht, kann ich nicht sicher sein, dass dieser problematische Fall vielleicht doch eintritt, da threads vom OS  jederzeit aktiviert//deaktiviert werden können. Und normalerweise wird heutzutage auf ein RDBMS multithreaded (oder zumindest multi-prozess) zugegriffen. Gut. Ich kann zb. in Java mit synchronized arbeiten. Das ist aber nervig, fehleranfällig und schlecht für die Performance.
Bei Oracle und PosGres kann man den Prim-Key Wert vor dem insert erzeugen. Das ist viel besser. Da können solche Konfusionen nicht auftreten.
MySQL ist hier wie DB2. Die Funktion heisst nur leicht anders (vergessen, trags nach).
In Posgres mach ich das einfach so:
1. Eine Sequenz (besondere Form von Table) erzeugen.
Code
Create Sequence Seq_Person;

Um an den nächsten Sequenz-Wert zukommen gibt es eine spezielle Funktion:
Das kann ich dann in der selben Transaktion vor dem insert aufrufen und den PrimKey über den Insert setzen.
Code
Select nextval('Seq_Person'); 
In meinen Augen ist das viel sauberer. Ich kann das natürlich in DB2 mit eigenen Tabellen nachprogrammieren, aber das wäre deutlich mehr Code.

2.
Die nächsten Punkte betreffen den ziemlich zentralen - nenn den mal - Performance versus Datenintegritäts-Konflikt - bei gleichzeitigen transaktionalen Multi-User-Zugriff.
Es gibt ja in SQL-92 diese 4 Transaktionslevel:
- READ_UNCOMMITED (andere Transaktionen können nicht-commitete inserts, updates dieser Transaktion lesen)
Bemerkung: sehr performant aber Chaos für Datenintegrität
- READ_COMMITED (andere Transaktionen können nicht-commitete inserts, updates dieser Transaktion nicht lesen)
Bemerkung: schnell und am gebräuchlichsten
- REPEATABLE_READ (Auf Datensätze, mit denen diese Transaktion selects gemacht hat, ist ein Lock für andere Transaktionen)
Bemerkung: eventuell schon problematisch von der Performance
- SERIALIZABLE (ganze Tabellen auf die diese Transaktion selects gemacht hat, sind für andere Transaktionen gesperrt)
Bemerkung: inperformant bei multi-User Zugriff.

Es gibt diese neuen und sehr schlanken Datenbanken wie Derby und HSQLDB. Problem von denen ist, dass sie ausser READ COMMITED kein anderes Transaktionslevel unterstützen. MySQL hat bei Transaktionen traditionell starke Schwächen. Mit einem neuen Tabellentyp namens innodb ist das ein bischen besser geworden.

3. Wieder Oracle und PostGres unterstützen eine Select **** for UPDATE Syntax.
Damit kann ich die so gefundenen Datensätze unter READ COMMITED Transaktionslevel locken (sehr cool). Es ist dann praktisch für diese Selects wie REPEATABLE_READ aber eben nicht für alle Selects dieser Transaktion (feingranularer). DB2 scheint das auch nicht zu haben. MySQL natürlich auch nicht.


btw: PosGreSQL kann man mittlerweile auf Windows ohne cygwin laufen lassen. Funktioniert auch bei mir bisher gut und es ist wirklich eine tolle Datenbank. Bei allen gibt es inzwischen ein GUI-Administrier/SQL Tool. Für alle, die sich nicht unbedingt trauen, alles über Kommandozeile zu machen (was aber hier oft bedeutend schneller ist).


Gruß Axel
« Letzte Änderung: 15.05.05 - 19:30:32 von Marinero Atlántico »

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz