Speicherplatz sollte man aber nicht außen vor lassen, wenn man Geschwindigkeit will. Die höchsten Kosten verursachen nun einmal Festplattenzugriffe.
Das sich Queries mit den selben Ergebnissen wiederholen ist unwahrscheinlich.
Ich sprach von änlichen Abfragen und Cache.
Aber gut, hier eine grobe Vorstellung von dem worum es geht. (Reduziert und vereinfacht auf relevante Daten für eine Standardabfrage.)
Bisheriges Design
Tabelle user: user_id, loginname
Tabelle objekte_user: objekt_id, objekt_typ_o_adresse, eltern_objekt_id, adress_id, name, beschreibung
Tabelle adressen: adress_id, adresse
objekt_id ist eine serial, objekt_typ_o_adresse ist entweder “ordner” oder eine adress_id, adress_id die 36 Trilliaden Sache.
Und Du hast nun für jeden User eine eigene Objekt-Tabelle?
Warum kann objekt_typ_o_adresse einmal ein String (“ordner” ) sein und einmal ein Int (adress_id)? Warum nicht NULL, wenn es keine adress_id ist? Und wie kommst Du bei 6 Milliarden Menschern derzeit auf 36 Trilliarden Adressen?
Nutzer surft auf eine URL, in der loginname sowie objekt_id enthalten sind.
Skript sucht nach der user_id zum gelieferten loginname.
Skript sucht in der entsprechenden Objektetabelle nach der objekt_id. (Hiernach kommt eine kleine Ausgabe.)
Abschließend sucht das Skript aber nach allen Objekten die die objekt_id der letzten Abfrage als eltern_objekt_id haben und nicht objekt_typ_o_adresse “ordner” und verknüpft diese Anhand der adress_id mit der Tabelle adressen.
Aha. Das Script sucht anhand der Resultate des verhergehenden Selects, oder wie? Das Script ist dann sicher noch PHP oder sowas, ja? Und ich dachte, es sollte schnell werden…
Warum nicht alles in einer Abfrage?
Schnellschuß:
test=*# select * from objekte_user;
objekt_id | user_id | typ | eltern_objekt | adress_id
-----------+---------+-----+---------------+-----------
1 | 1 | | | 1
2 | 1 | | 1 | 1
(2 rows)
test=*# select * from adressen ;
id | adresse
----+----------
1 | adresse1
2 | adresse2
(2 rows)
test=*# select u.login, o.*,a.adresse from objekte_user o left join usr u on (u.usr_id=o.user_id) left join adressen a on (a.id=o.adress_id) where o.eltern_objekt in (select objekt_id from objekte_user o left join usr u on (u.usr_id=o.user_id) ) and u.login='foo';
login | objekt_id | user_id | typ | eltern_objekt | adress_id | adresse
-------+-----------+---------+-----+---------------+-----------+----------
foo | 2 | 1 | | 1 | 1 | adresse1
(1 row)
(man könnt schauen, ob es was bringt, im inneren select noch den user zu begrenzen)
(Adressen ist in einer eigenen Tabelle, für den nicht unwahrscheinlichen Fall, dass eine Adresse mehrmals von mehreren Nutzern geführt wird. Die Nutzer sollen allerdings die Möglichkeit haben den Einträgen eigenen Namen und Beschreibungen zu geben.)
6 Milliarden Menschen nutzen aus einem Pool von 36 Trillionen Adressen diese sehr wahrscheinlich also gemeinsam.
In meinen Augen insgesamt ein normalisiertes Datenbankdesign mit der Hoffnung auf gute Performance.
Ja, wenn man passend abfragt. Eine Aufteilung der Tabelle auf die User ist IMHO komplett unsinnig. Falls Du das dennoch noch immer willst, wirst Du zum Abfragen dynamische SQL-Befehle generieren dürfen. Oder den ‘Trick’ über Schemas gehen.
Man könnte nun die Tabellen für objekte kombinieren und gewissermaßen aus user_id und objektid einen geteilten Schlüssel machen. Technisch keine Sache, aber die Geschwindigkeit interessiert mich. Das Ergebnis muss im Sekundenbruchteil parat sein.
Wird es. Passende Indexe vorausgesetzt. Und eine aktuelle Version. Man braucht im übrigen keine zusammengesetzten Schlüssel bzw. Indexe. Das hier ist nicht MySQL, was pro select und table nur einen Index nutzen kann.
Andreas