Datenbankkonzeption



  • Naja, kann schon Sinn machen die Daten jedes Users in eigenen DBs zu speichern. Oder auch nicht, so allgemein kann man das nicht sagen.

    Vorteile wären z.B. die höhere Geschwindigkeit bei (oft nicht vermeidbaren) Table-Scans und das unproblematische Handling bei z.B. Löschung eines Accounts.

    Nachteile wären z.B. dass das Design unüblich ist (POLA Verletzung etc.) und dass der Overhead per User relativ gross ist (=schlecht bei vielen Usern die jeweils wenig "Nutzdaten" haben).

    ----

    Eine Möglichkeit mehrere DBs zu vermeiden wäre einfach nur verschiedene Tables zu verwenden.
    Dazu kann man Schemas verwenden (im Prinzip sowas wie Namespaces), oder auch einfach Prefixe bzw. Postfixe bei den Tablenamen.

    Die meisten Vorteile der "mehrere DBs" Lösung bleiben dabei wohl erhalten.



  • hustbaer schrieb:

    Naja, kann schon Sinn machen die Daten jedes Users in eigenen DBs zu speichern. Oder auch nicht, so allgemein kann man das nicht sagen.

    Vorteile wären z.B. die höhere Geschwindigkeit bei (oft nicht vermeidbaren) Table-Scans und das unproblematische Handling bei z.B. Löschung eines Accounts.

    Nachteile wären z.B. dass das Design unüblich ist (POLA Verletzung etc.) und dass der Overhead per User relativ gross ist (=schlecht bei vielen Usern die jeweils wenig "Nutzdaten" haben).

    ----

    Eine Möglichkeit mehrere DBs zu vermeiden wäre einfach nur verschiedene Tables zu verwenden.
    Dazu kann man Schemas verwenden (im Prinzip sowas wie Namespaces), oder auch einfach Prefixe bzw. Postfixe bei den Tablenamen.

    Die meisten Vorteile der "mehrere DBs" Lösung bleiben dabei wohl erhalten.

    Das ist dochjetzt nicht dein Ernst 😮 was denn für Tablescans, wozu hat man denn Indizes, und die Löschung ist genau so einfach wie die Neuanlage.



  • deejey schrieb:

    Das ist dochjetzt nicht dein Ernst 😮

    Doch, natürlich.

    deejey schrieb:

    was denn für Tablescans, wozu hat man denn Indizes,

    Es gibt genügend Abfragen die man mit Indexen nicht bzw. nicht sinnvoll erschlagen kann.

    deejey schrieb:

    und die Löschung ist genau so einfach wie die Neuanlage.

    Ja, klar. Kann aber mächtig dauern wenn es viele Zeilen sind. Wenn man auf grob fragmentierte Tabellen und Indexe steht sollte man es aber natürlich so machen.

    Kann es sein dass dir einfach die praktische Erfahrung mit Datenbanken etwas fehlt?



  • Es mag vielleicht tatsächlich Fälle geben, wo das sinnvoll ist, aber ich halte für so unwahrscheinlich, dass ich hier tatsächlich den Rat geben würde, dass es nicht sinnvoll ist. Zumindest hat der TE noch kein KO Kriterium genannt, warum das sinnvoll sein könnte.



  • Ja, stimmt.

    Dass es nicht üblich ist hab' ich ja schon geschrieben.

    Ist auf jeden Fall eine Sache die man nicht machen sollte so lange man keine guten Gründe dafür hat.
    Man müsste halt wissen was die Anforderung "Daten sollten so gut wie möglich voneinander getrennt werden" genau bedeutet. Also wo die herkommt, was "trennen" heisst, wieso soll getrennt werden etc.



  • hustbaer schrieb:

    deejey schrieb:

    Das ist dochjetzt nicht dein Ernst 😮

    Doch, natürlich.
    ...
    Kann es sein dass dir einfach die praktische Erfahrung mit Datenbanken etwas fehlt?

    Ja, das wird's wohl sein



  • Ja, das kam jetzt wieder ein bisschen grosskotzig rüber (von mir meine ich natürlich). Sorry.

    Ist aber einfach so, dass - wie gesagt - sich Table-Scans in der Praxis einfach oft nicht vermeiden lassen. *
    Zumindest nicht bei Datenbanken die nur klassische "normale" Indexe können (=keine "spatial" Indexe).

    Klar, man kann die Table-Scans durch Index-Scans ersetzen indem man Covering-Indexes macht. Aber das hat halt wieder Kosten/andere Nachteile. Und wenn der "Covering-Index" mal gross wird, weil man einfach viele Spalten braucht, dann hat man damit kaum mehr was gewonnen.

    Zumindest ist das meine Erfahrung.

    *:
    Beispiele: Du hast nen Index, und willst 1% aller Zeilen über diesen Index auswählen. z.B. weil du 100 User hast und jeder User hat inetwa gleich viele Zeilen, und du willst jetzt die Zeilen von User X. Die Tabelle ist entweder gar nicht sortiert, oder hat (weil für andere Abfragen wichtig), nen Clustered-Index auf eine Spalte die NICHT die User ID ist. Effektiv macht eine (gute) DB hier dann einen Table-Scan, weil sie weiss dass es billiger ist nen Table-Scan zu machen (=linear lesen) als 1% aller Zeilen einzeln "rauszupicken" (random access).

    Oder Abfragen die Tests auf viele unterschiedliche Felder im WHERE Teil machen. Auch hier kann es schneller sein einen Table-Scan zu machen als zu versuchen die Abfrage irgendwie über die Indexe zu optimieren. Kommt halt drauf an ob es billiger ist viele Index-Intersections zu machen, und die Zeilen dann wieder einzeln aus dem Table rauszupicken, oder eben 1x den ganzen Table linear zu lesen.



  • Gut vlt. reden wir auch nur aneinander vorbei, ich kenne den DB-Umgang nur mit Massendaten (kaufmännische ERP-Anwendungen), da können locker dutzende Millionen Datensätze in Tabellen vorkommen. Die Verwaltung der Indizes bzw. Covered-Indices ("Views") ist alle mal schneller als Fullscans, auch führt die DB heutzutage doch selbst Informationen über optimierte Zugriffe und entscheidet selbst, welchen Index sie benutzen will, ansonsten kann man über Hints manuell versuchen es zu verbessern. Es hängt auch stark vom DB-Design ab wie sich die Zugriffe verhalten.

    naja letzendlich verstehe ich immer noch nicht warum genau der TE das so machen will, das DB-Layout haut einen doch nicht um, und die Daten sind doch durch den Primärschlüssel sauber getrennt 😮



  • Danke für die bisherigen Ratschläge. Die Daten sollen auch offline verfügbar gemacht werden. Dazu gibt es eine Anwendung, die natürlich ebenfalls SQL kann und in der man (nachdem man die Datenbank aus der Online-Plattform exportiert hat) ganz normal weiterarbeiten kann. Sämtliche Daten kommen wie gesagt vom Nutzer (per Eingabe). Meine Überlegung war dabei, dass es einfacher ist, eine einzelne Datenbank pro User zu exportieren. Die Offline-Anwendung benötigt ja eh eine Datenbank, auf die dann auch immer nur ein User zugreifen kann. Daher hatte ich überlegt, das für die Online-Variante auch direkt so zu machen. Wenn der Nutzer seine offline eingetragenen Daten hochladen möchte, müsste ich ja dann nur die Offline-DB als neue Datenbank importieren und bei Erfolg könnte ich die "alte" Online-DB löschen (natürlich in meiner UserInfo-Table vorher noch den Namen der neuen DB eintragen).
    Mache ich das alles mit einer Tabelle, muss ich ja jeden Datensatz updaten lassen und vorher ein Backup in einer extra DB anlegen, falls beim Import (warum auch immer) etwas schief läuft. Wenn ich ansonsten aus irgendeinem Grund eine Inkonsistenz in einer Tabelle habe, sind auch gleich alle User betroffen. Das Argument, dass Banken das genauso machen würden, ist für mich nicht wirklich von Gewicht, da Banken (zumindest hoffe ich das) eine Menge Zeit und Mühe investieren, um jederzeit eine hunderprozentige Konsistenz zu gewährleisten (ich gehe mal davon aus, dass die Daten stets redundant, aber natürlich getrennt gespeichert werden und davon dann jeweils in mittelkurzen Abständen BackUps gemacht werden). Bei dem Projekt ist zwar ein tägliches BackUp der DB geplant, allerdings ist das wohl kaum mit dem einer Bank zu vergleichen (wie gesagt, hoffe ich zumindest).

    Packe ich alle User Daten in die selben Tabellen, sehe ich persönlich einen höheren Aufwand, um die Daten dann auch bei den häufigen Im- und Exports sauber zu trennen. Meine Überlegung kann man dabei vllt. mit verschiedenen Währungen vergleichen. Klar kann man Scheine von drei verschiedenen Währungen in ein Fach im Geldbeutel packen. Wenn ich die aber gleich in jeweils einzelne Fächer teile, habe ich im entsprechenden Land nicht das Problem, dass ich von den 30 Scheinen erstmal die richtige Währung raussuchen muss, sondern ich gucke in ein Fach und weiß, da müssen die Euros drinne sein. Das Durchforsten der restlichen 20 1-Dollar-Noten und der paar britischen Pfund entfällt und ich sehe immer sofort, wie es um meine Devisen (zumindest mengenmäßig, wenn auch nicht wetmäßig) bestellt ist.

    Das waren so meine Überlegungen dazu.



  • deejey schrieb:

    Gut vlt. reden wir auch nur aneinander vorbei, ich kenne den DB-Umgang nur mit Massendaten (kaufmännische ERP-Anwendungen), da können locker dutzende Millionen Datensätze in Tabellen vorkommen.

    Tabellen mit dutzenden Millionen Datensätzen sind nach meiner Erfahrung eigentlich gerade bei ERP Anwendungen eher selten. Ist aber eigentlich auch egal, wo die Daten herkommen spielt nicht wirklich eine Rolle.

    deejey schrieb:

    Die Verwaltung der Indizes bzw. Covered-Indices ("Views") ist alle mal schneller als Fullscans

    Eieiei.
    1: Tu dich mal nicht täuschen.
    2: Du vermischt hier zwei Dinge, nämlich INSERT/UPDATE/DELETE und SELECT Performance. Ein Index kostet (neben Platz) Performance bei INSERT/UPDATE/DELETE. Er bringt dagegen Performance wo Datensätze gefunden werden müssen, also u.A. bei SELECTs.
    3: Covered-Index ist Quatsch, du meinst vermutlich Covering-Index
    4: Ein Covering-Index ist keine View, auch wenn ähnlichkeiten zu einer Indexed-View bestehen

    deejey schrieb:

    auch führt die DB heutzutage doch selbst Informationen über optimierte Zugriffe und entscheidet selbst, welchen Index sie benutzen will

    Die DB kann aber nur das tun was die DB eben tun kann.
    Und wenn die DB nur normale 1-Dimensionale B-Tree/B*Tree/B+Tree Indexe kann, dann kann sie eben nicht mehr.
    Dann kann sie auch keine multidimensionalen Range-Queries direkt über Indexe machen.
    Klar, sie kann Index-Intersections und vielleicht noch 1-2 weitere Tricks anwenden, aber sie muss im Endeffekt immer viel mehr Zeilen angreifen als nach der vollständigen WHERE Bedingung übrig bleiben.
    Und damit kommt es einfach vor dass ein Table-Scan im Endeffekt immer noch am schnellsten ist.



  • sqlc schrieb:

    Die Daten sollen auch offline verfügbar gemacht werden.

    SQLite?

    sqlc schrieb:

    Meine Überlegung war dabei, dass es einfacher ist, eine einzelne Datenbank pro User zu exportieren. Die Offline-Anwendung benötigt ja eh eine Datenbank, auf die dann auch immer nur ein User zugreifen kann.

    SQLite.



  • sqlc schrieb:

    Meine Überlegung war dabei, dass es einfacher ist, eine einzelne Datenbank pro User zu exportieren.

    Vielleicht. Wobei Export ja nicht so schwer ist, hängst halt ein WHERE user_id = dran.
    Aber mit mehreren Tabellen/Datenbanken brauchst du zusätzliche Logik beim Aufbauen der Queries, damit du entscheiden kannst, welche Tabelle du nimmst. Dann evtl. zusätzlich eine Verwaltung, weil du wissen musst, was für Tabellen es alles gibt. Du brauchst DAL Queries, zum Anlegen und Löschen der zusätzlichen Tabellen. Dann wirst du später Probleme bekommen, wenn du irgendwelche Statistiken/Auswertungen/Vergleiche machen willst, die sich auf mehrere Benutzer beziehen. Das sind nur ganz spontane Überlegungen, man kann sicher viel mehr Gründe finden, die dafür oder dagegen sprechen. Aber wenn man nicht genau weiß, was man macht, dann ist es im Zweifelfall besser, die etabliertere Variante zu wählen.



  • TyRoXx schrieb:

    sqlc schrieb:

    Die Daten sollen auch offline verfügbar gemacht werden.

    SQLite?

    Das hatte ich auch gedacht, da ich mich mit SQLite schon etwas auskenne und SQLite auch wohl am meisten eingesetzt wird (bei serverlosen Datenbanken).

    Mechanics schrieb:

    Aber mit mehreren Tabellen/Datenbanken brauchst du zusätzliche Logik beim Aufbauen der Queries, damit du entscheiden kannst, welche Tabelle du nimmst.

    Aber doch nur, wenn ich userübergreifend eine Abfrage machen will, oder? Der einzelne User hat ja mit den Daten anderer User nichts am Hut.



  • sqlc schrieb:

    Aber doch nur, wenn ich userübergreifend eine Abfrage machen will, oder? Der einzelne User hat ja mit den Daten anderer User nichts am Hut.

    Aber woher weißt du, wie die Tabelle des Benutzers heißt? Du brauchst zumindest zusätzlichen Code, um das zu verwalten und herauszufinden und dann musst du das in deine Queries einbeziehen. Dann brauchst du wahrscheinlich auch eine Benutzerverwaltung, die Benutzer anlegen und löschen kann? Also brauchst du DAL Statements zum Anlegen/Löschen von Tabellen.
    Und dass du jetzt keine userübergreifenden Funktonen hast, heißt ja nicht, dass es so bleiben wird. Irgendwann will man doch Statistiken usw. einbauen.



  • hustbaer schrieb:

    deejey schrieb:

    Gut vlt. reden wir auch nur aneinander vorbei, ich kenne den DB-Umgang nur mit Massendaten (kaufmännische ERP-Anwendungen), da können locker dutzende Millionen Datensätze in Tabellen vorkommen.

    Tabellen mit dutzenden Millionen Datensätzen sind nach meiner Erfahrung eigentlich gerade bei ERP Anwendungen eher selten. Ist aber eigentlich auch egal, wo die Daten herkommen spielt nicht wirklich eine Rolle.

    deejey schrieb:

    Die Verwaltung der Indizes bzw. Covered-Indices ("Views") ist alle mal schneller als Fullscans

    Eieiei.
    1: Tu dich mal nicht täuschen.
    2: Du vermischt hier zwei Dinge, nämlich INSERT/UPDATE/DELETE und SELECT Performance. Ein Index kostet (neben Platz) Performance bei INSERT/UPDATE/DELETE. Er bringt dagegen Performance wo Datensätze gefunden werden müssen, also u.A. bei SELECTs.
    3: Covered-Index ist Quatsch, du meinst vermutlich Covering-Index
    4: Ein Covering-Index ist keine View, auch wenn ähnlichkeiten zu einer Indexed-View bestehen

    deejey schrieb:

    auch führt die DB heutzutage doch selbst Informationen über optimierte Zugriffe und entscheidet selbst, welchen Index sie benutzen will

    Die DB kann aber nur das tun was die DB eben tun kann.
    Und wenn die DB nur normale 1-Dimensionale B-Tree/B*Tree/B+Tree Indexe kann, dann kann sie eben nicht mehr.
    Dann kann sie auch keine multidimensionalen Range-Queries direkt über Indexe machen.
    Klar, sie kann Index-Intersections und vielleicht noch 1-2 weitere Tricks anwenden, aber sie muss im Endeffekt immer viel mehr Zeilen angreifen als nach der vollständigen WHERE Bedingung übrig bleiben.
    Und damit kommt es einfach vor dass ein Table-Scan im Endeffekt immer noch am schnellsten ist.

    Ich bin zu alt für diese Scheisse, hätte ich bloß mein Maul gehalten



  • @deejey
    Hast du schonmal partitionierte Tabellen verwendet?

    Aus
    http://www.oracle.com/technetwork/issue-archive/2006/06-sep/o56partition-090450.html

    Performance. This, of course, is the primary objective of many partitioning schemes. Performance advantages come from partition pruning or partitionwise joins, so if your queries do a lot of full-table scans, partitioning will help immensely, because partitions will limit the scope of the search. Consider a scenario involving the TRANS table. Suppose everyone is interested in the aggregate sales figures but product managers (PMs) are interested in the sales figures of their respective products only, not in all the sales. So the PM of product code "8" issues this SQL statement several times an hour:

    `select trans_dt, sum(trans_amount), avg (trans_amount),

    max(trans_amount), min(trans_amount)

    from trans

    where product_code = 8

    group by trans_dt;`

    Ein Index auf product_code hilft dir dabei nur, wenn er hoch selektiv (<< 1%) ist ODER "clustered" ODER "covering" (für diese Abfrage). Wie selektiv der Index ist kann man sich meist nicht aussuchen - die Daten sind die Daten und die kann man nicht einfach so ändern. Was "clustered" Indexe angeht so haben diese wieder eigene Nachteile, und vor allem: was wenn man schon einen auf einer anderen Spalte hat, und den auch braucht? Bleibt noch ein covering Index. Wenn der Tradeoff den man dabei eingeht (mehr Platz, schlechtere INSERT/UPDATE/DELETE Performance, ...) OK ist, dann ... OK. Sicher die deutlich bessere Lösung, weil viel viel wartungsfreundlicher.

    Aber wenn nicht, dann kann man eben noch partitionieren.
    Ist natürlich auch wieder ein Tradeoff, wird ja auch vieles schlechter durch Partitionierung.

    Und Daten in getrennte Tables zu stecken ist vom Prinzip her nix anderes als Partitionierung. Nur dass die DB-Engine davon nix weiss, und sich daher auch nicht automatisch um z.B. das Bilden von UNIONs über die Partitionen kümmern kann.



  • Mechanics schrieb:

    sqlc schrieb:

    Aber doch nur, wenn ich userübergreifend eine Abfrage machen will, oder? Der einzelne User hat ja mit den Daten anderer User nichts am Hut.

    Aber woher weißt du, wie die Tabelle des Benutzers heißt? Du brauchst zumindest zusätzlichen Code, um das zu verwalten und herauszufinden und dann musst du das in deine Queries einbeziehen. Dann brauchst du wahrscheinlich auch eine Benutzerverwaltung, die Benutzer anlegen und löschen kann? Also brauchst du DAL Statements zum Anlegen/Löschen von Tabellen.
    Und dass du jetzt keine userübergreifenden Funktionen hast, heißt ja nicht, dass es so bleiben wird. Irgendwann will man doch Statistiken usw. einbauen.

    Da stimme ich prinzipiell ja zu. Ich schildere aber nochmal kurz, wie ich mir das gedacht habe:
    In der Online-Variante gibt es eine Datenbank, die nutzerübergreifende Informationen speichert (Login-Daten, etc.). In dieser Datenbank steht neben den Nutzern auch die jeweils zugeordnete Nutzer-Datenbank (ausgehend davon, dass jeder Nutzer eine eigene Datenbank hat). Ich muss jeder Nutzer-DB bei der Erstellung eh einen Namen verpassen, da ist es dann kein Problem, diesen Namen in der System-DB nutzerbezogen zu speichern. Die Tabellen in den Nutzer-DBs sind namenstechnisch identisch (in meinem Fall 'References', 'Records' und 'RecordFacets').

    So stelle ich mir nach diesem Schema ein Login vor:

    Eingabe Login-Daten -> Zugriff auf System-DB -> Bei erfolgter Verifizierung: Ermitteln der Nutzer-DB und Erstellen der Session -> Connect mit der Nutzer-DB -> Nutzer kann loslegen
    

    Hätte ich für jeden Nutzer extra Tabellen wäre das natürlich umständlich, da ich jeden Tabellen-Namen speichern müsste und bei Bedarf den dann ermitteln muss. Alternativ könnte ich (wenn ich für jeden Nutzer extra Tabellen anlegen würde) auch immer die gleichen Namen nehmen und dann die User-Tabellen einfach mit der UserID (im Beispiel '1' und '2') prä- oder suffixen.

    Also Anstatt:

    SystemDB
      UserInfo
        - Id: "1", Name: "Karl", Password: "hashash", UserDb: "UserDB1"
        - Id: "2", Name: "Peter", Password: "hsahsah", UserDb: "UserDB2"
    UserDB1
      References
      Records
      RecordFacets
    UserDB2
    ...
    

    hätte ich dann sowas

    SystemDB
      UserInfo
        - Id: "1", Name: "Karl", Password: "hashash"
        - Id: "2", Name: "Peter", Password: "hsahsah"
    UserDB
      user1_References
      user1_Records
      user1_RecordFacets
      user2_References
      user2_Records
      user2_RecordFacets
      ...
    

    Das wäre glaube ich sogar die bessere Lösung, da ich so immer zur gleichen DB connecten kann, die Daten immer noch strikt getrennt sind und auch ein Export kaum aufwendiger sein wird, als mit der "eine-db-pro-nutzer"-Variante. Die Präfixe kann man ja in der Session speichern und einfach bei einer Query vorne ranhängen.

    Kann man auf meine Datei eigentlich zugreifen? Weil dort hatte ich auch eine UserInfo-Tabelle abgebildet, weswegen ich glaube ich etwas irritiert war. Also die Nutzerverwaltung ist ja schon eingeplant (für Online).

    Danke nochmals für die Anregungen


Anmelden zum Antworten