Wie am besten sehr viele Datensätze in SQLAlchemy speichern

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

Ich hab meine ersten Schritte erfolgreich in SQlAlchemy getätigt und brauche jetzt einen Ratschlag um relativ viele Datensätze zu speichern.
Es handelt sich um Nutzerdaten. Bis jetzt hab ich lediglich neue Nutzer hinzugefügt und diese aktualisiert. Um das ganze auf die nächste Stufe zu bringen, müsste ich jeden Nutzer, welcher aktualisiert werden soll nicht überschreiben, sondern zusätzlich speichern.
Es werden einige Tausend Nutzer sein und voraussichtlich jede Stunde eine Aktualisierung erfolgen. D.h. es werden sehr viele Datenmengen gespeichert werden müssen.
Das ganze soll dazu dienen die Veränderung der Daten über einen Zeitraum darzustellen. Ungefähr 20 verschiedene Daten abgesehen vom Zeitstempel und Nummerierung kommen jeweils dazu.

Meine jetzige Umsetzung ist für die paar Tausend Nutzerdaten ausreichend, wenn jedoch jede Aktualisierung gespeichert werden soll, sollte das ganze möglichst Ordentlich strukturiert sein.
Die einzelnen Daten sind ziemlich klein, werden sich aber nach einigen Monaten und Jahren Laufzeit stark vergrößern.

Hat jemand Erfahrung wie man am besten die Daten am besten strukturiert? Einzelne Datenbanken pro Nutzer oder pro Nutzer eine Tabelle in einer Datenbank? Wäre cool, wenn jemand hierzu einige Tipps hat. :)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dami123: die Struktur der Datenbank kommt stark auf die Art der Daten an: ob für jeden der 20 Daten eine eigene Tabelle sinnvoll ist, oder alles in eine Tabelle gesteckt wird, z.B. Tabellen pro Nutzer oder sogar Datenbanken sind nie sinnvoll, weil Du Dir damit das Arbeiten mit den Daten verbaust. Datenbanken sind dafür ausgelegt, mit vielen Datensätzen zu arbeiten.
BlackJack

@Dami123: Fang bloss nicht an die Tabellen selbst variabel anzulegen.

Die beiden üblichen Ansätze sind eine Tabelle wo dann halt auch mehrere Datensätze pro Benutzer drin stehen. Und dann schau erst einmal ob es überhaupt ein Problem gibt das man lösen muss. Falls das Abfragen des aktuellen Zustands zu lange dauert könnte man eine Spalte mit einem Flag einführen in dem der jeweils aktuellste Datensatz für jeden Benutzer markiert ist. Dann muss man beim aktualisieren dieses Flag beim bisherigen letzten Datensatz löschen und beim neu eingefügen setzen. Oder man führt zwei Tabellen, eine wo nur ein Datensatz pro Benutzer drin steht der dann aktualisiert wird, und eine wo die Datensätze zusätzlich als Historie gespeichert werden.
bfm
User
Beiträge: 88
Registriert: Donnerstag 14. März 2013, 09:42

Hallo,

wenn ich das richtig verstanden haben, sollen die Datensätze historisch gespeichert werden.

In unserer Lohnverrechnungssoftware werden hierzu in bestimmten Tabellen zB Personendaten (Name, Vorname, Adresse, Geburtsdatum) zusätzlich zu jedem Datensatz zwei Felder mit "historisches Datum von" und "historischtes Datum bis" geführt. Im aktuellen quasi letzten Datensatz ist das bis-Datum 31.01.2099. (SAP nimmt zB 31.13.9999)
In Abfragen kann somit festgelegt werden, zu welchem Stichtag die Stammdaten herangezogen werden sollen, dh man kann abfragen, welche Daten zum Datum X bei dem Mitarbeiter gültig waren oder sein werden (falls schon zukünftige Historien angelegt sind). Mit entsprechenden Indizes auf der Datenbank dürfte auch ein PC kein Problem mit mehreren 100.000 Datensätzen haben.

mfg
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Einem Nutzer werden also ca. 20 verschiedene Attribute zugeordnet und diese Attribute können sich mit der Zeit ändern. Die Historie dieser Änderungen soll auch in der Datenbank gespeichert werden. Ist das so korrekt?
Wenn ja, dann wäre noch wichtig zu wissen ob sich die ca. 20 Attribute alle immer gleichzeitig ändern oder von jeder Änderung immer nur einzelne Attribute betroffen sind?
Gibt es Attribute die sich nie ändern (z.B. Geburtsdatum und Geschlecht)?

Neben Python- und Datenbank-Wissen empfehle ich Dir auch, Dir die juristischen Basics zur Verarbeitung von personenbezogenen Daten anzueignen (Domänenwissen ist immer gut).
a fool with a tool is still a fool, www.magben.de, YouTube
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Dami123: Du kannst die Historie aller Benutzer in einer einzigen neuen Tabelle abspeichern. Als Primärschlüssel nimmst du den Zeitstempel der Änderung. In den Programmcode zum Speichern von Veränderungen muss dann nur eine Zeile zum Auslesen der aktuellen Daten für den Benutzer eingefügt werden. Und dann werden innerhalb einer Transaktion zuerst die Veränderungen in der aktuellen Tabelle und anschließend die zuvor gelesenen alten Daten in die Historie samt Zeitstempel geschrieben. Erst danach würde ich beides Committen.

Über die Anzahl der Datensätze in der stetig anwachsenden Historie würde ich mir erstmal keine großen Gedanken machen. Genau für sowas sind Datenbanken ja ausgelegt. Sicherheitshalber kann man natürlich recherchieren, ob die Datenbank irgendwelche Grenzen für einzelne Tabellen festlegt. Die "natürliche" Grenze ist natürlich immer der zur Verfügung stehende Speicherplatz, d.h. man sollte von Zeit zu Zeit nachschauen, welche Größe die Tabelle inzwischen angenommen hat. Aber hier sprechen wir wahrscheinlich in Dimensionen von Jahren und nicht etwa von Tagen oder Wochen.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

MagBen hat geschrieben:dann wäre noch wichtig zu wissen ob sich die ca. 20 Attribute alle immer gleichzeitig ändern oder von jeder Änderung immer nur einzelne Attribute betroffen sind?
Und was fängt man mit dieser Information an? Willst du etwa so eine Art Diff für jede Änderungen beim Speichern in die Historie implementieren? Ich finde, solche Fragen sollten eher beim Schritt des Interpretierens der Daten beantwortet werden, d.h. wenn entsprechende Abfragen gemacht werden dessen Ergebnisse ggf noch gemäß der Fragestellung angepasst werden müssen. Beim Schreiben würde ich das jedenfalls nicht so komplex machen.
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

snafu hat geschrieben:Und was fängt man mit dieser Information an?
Bevor man eine Datenbank entwirft ist es immer wichtig zu wissen, wie sie benutzt werden soll.
Wenn alle 20 Attribute in einer Zeile gespeichert werden und einige davon vielleicht auch noch große Strings sind, dann würde ich nicht eine neue Tabellenzeile (mit allen 20 Attributen) einfügen, wenn sich ein einzelnes Int-Flag geändert hat.
a fool with a tool is still a fool, www.magben.de, YouTube
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@MagBen: mit der Größe zu Argumentieren ist ein schwacher Hebel, Speicherplatz ist billig. Viel gewichtiger ist die Frage, welche Fragestellungen man an die Attribute hat. Wenn man wissen will, wann sich welches Attribut geändert hat, dann wäre es umständlich, alle Datensätze durchzusehen, ob das Attribut A das selbe ist, wie im Datensatz davor und dem davor, usw.
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

Danke für die Antworten.

Um die Art der zu speichernden Daten etwas genauer darzustellen:
Es gibt eine unbegrenzte Zahl an Benutzern.
Jeder Benutzer hat ca. 20 Daten, die gespeichert werden müssen. Mit Daten gemeint: (name: xy, userid: 999, alter: 99, .....) <- feste Daten zusätzlich verändernde Daten wie Anzahl an Beiträgen etc.
Jede Stunde werden die Daten des Users empfangen und sollen gespeichert werden, die alten Daten (vorheriger Stunde etc.) werden nicht überschrieben oder aktualisiert.

Umsetzungsvorschläge:
  • A: Für jeden Benutzer eine Datenbank mit einer Tabelle, wo jeder neue Eintrag hinzugefügt wird.

    B: Für jeden Benutzer eine Tabelle in einer Datenbank, wo jeder Eintrag hinzugefügt wird.

    C: Alle Benutzer in einer Tabelle in einer Datenbank.
Finde den Vorschlag B am sinnvollsten.

Daten, die sich nicht ändern werden, werde ich vererbt speichern, um Speicher zu sparen.
Über die Rechtslage der Datenspeicherung bin ich informiert.
Der Zugriff auf die Daten sollte durch den Timestamp relativ flott sein.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Dami123 hat geschrieben:Daten, die sich nicht ändern werden, werde ich vererbt speichern, um Speicher zu sparen.
Bitte definiere "vererbt speichern".

Wenn ich deinen Use-Case nicht gründlich missverstanden habe, dann brauchst du eine Tabelle um die User zu speichern und eine zweite Tabelle um die unterschiedlichen Bewegungsdaten zu speichern. Die zweite Tabelle muss zusätzlich einen Fremdschlüssel auf die Benutzertabelle haben.

Eine eigene Tabelle pro User ist, um es noch nett auszudrücken, völliger Humbug. Das konterkariert genau das, wofür relationale Datenbanken da sind. Man möchte nicht ernsthaft durch die Business-Logik des Programms neue Tabellen anlegen. So etwas macht man bei der Erstinstallation oder bei Updates. Die Business-Logik sollte sich auf CRUD-Operationen beschränken. Alleine die Vorstellung von eigenen Tabellen pro User tut mir nach über 25 Jahren DB-Erfahrung schon fast körperlich weh.

Bezüglich der Performance solltest du dir da auch keine Sorgen machen. Relationale Datenbanken sind dazu gebaut um genau mit so etwas umzugehen. Wenn du wirklich mal Performanceprobleme bekommen solltest, dann kannst du die typischerweise auf dem Datenbankserver lösen (z.B. durch eine Partitionierung der Tabelle oder eine optimierte Verteilung von Indizes und Tabellen auf unterschiedliche Platten-Subsysteme). Ich glaube allerdings aufgrund deiner Beschreibung nicht, dass du da wirklich in Probleme laufen wirst.
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

@/me
Danke für die Aufklärung! Tut immer gut konkrete Antworten zu hören.

Wenn ich den Ansatz nun richtig verstanden habe, speichere ich die alle Userdaten in einer Tabelle und alle Bewegungsprofile von allen verschiedenen Usern in einer zweiten Tabelle.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wie gesagt: Ich würde eine Tabelle machen, die die aktuellen Daten beinhaltet. Dort existieren genau so viele Zeilen wie Benutzer. Im Grunde kannst du es bestimmt dort bei deiner bisherigen Datenstruktur belassen. Was dazu kommt, wäre halt die zweite Tabelle, die mit Vergangenheitswerten gefüllt wird - quasi dein Archiv. Ins Archiv käme immer der Stand einer Zeile, der vor einer Änderung existiert hat. Im Archiv würde ich die Daten einfach so runter schreiben mit dem Zeitstempel des Eintragens als Primärschlüssel. Dieser Zeitstempel markiert also den Zeitpunkt bis zu dem die Daten als aktueller Wert existiert haben. Sicherlich sind aber auch andere Lösungen denkbar.
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

@snafu
Alles klar, dann werde ich dieses hier mehrfach aufgegriffene System übernehmen.


Danke für die Antworten. :)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dami123: snafus Vorschlag hat den Nachteil, dass man immer zwei Operationen für einen Datenbankeintrag braucht und man selbst darauf achten muß, dass die Daten immer konsistent bleiben. Bei Suchen mußt Du Dir immer überlegen, in welcher Tabelle. Mit einem Index auf den Zeitstempel sind Suchen nach dem aktuellen Datensatz sehr effizient. /me hat den besseren Vorschlag mit einer Tabelle für die statischen Daten und einer mit den dynamischen Daten gemacht:

Code: Alles auswählen

Tabelle User:
- User-ID
- Name
- Addresse
- Geburtsdatum (Alter ist keine sinnvolle Größe)
- usw.

Code: Alles auswählen

Tabelle Daten:
- id
- User-ID
- Zeitstempel
- Daten ...
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Mein Gedanke war halt, dass sich alle Angaben auch mal ändern können und man dann auch wirklich jede Änderung archivieren möchte. Beispiele für Änderungen an den Stammdaten: Umzug des Users, Umbenennung des Accounts, Verschreiber beim Geburtsdatum, neue Email-Adresse, etc. Es ist halt abhängig davon, ob man sich auf bestimmte Updates beschränken möchte (z.B. nur neue Forumsbeiträge) oder ob man wie gesagt alles, was geht, mitloggen will.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

snafu hat geschrieben:Mein Gedanke war halt, dass sich alle Angaben auch mal ändern können und man dann auch wirklich jede Änderung archivieren möchte.
Eine klassische Vorgehensweise wäre es, dafür Trigger in der Datenbank zu erstellen und diese das Logging bzw. die Archiwierung übernehmen zu lassen.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

snafu hat geschrieben:Wie gesagt: Ich würde eine Tabelle machen, die die aktuellen Daten beinhaltet. Dort existieren genau so viele Zeilen wie Benutzer. Im Grunde kannst du es bestimmt dort bei deiner bisherigen Datenstruktur belassen. Was dazu kommt, wäre halt die zweite Tabelle, die mit Vergangenheitswerten gefüllt wird - quasi dein Archiv. Ins Archiv käme immer der Stand einer Zeile, der vor einer Änderung existiert hat. Im Archiv würde ich die Daten einfach so runter schreiben mit dem Zeitstempel des Eintragens als Primärschlüssel. Dieser Zeitstempel markiert also den Zeitpunkt bis zu dem die Daten als aktueller Wert existiert haben. Sicherlich sind aber auch andere Lösungen denkbar.
Ich halte dieses Vorgehen auch eher für ungewöhnlich.

@Dami123:
Trenne die Daten eher nach Stammdaten (wenig Veränderung) und Bewegungsdaten, wie von /me schon vorgeschlagen wurde - also Tabelle1 mit Feldern wie Name, Adresse, Schuhgröße. Da kommen ALLE Nutzer rein. Tabelle2 mit den Bewegungsdaten enthält dann nur die schnell veränderlichen Werte mit Fremdschlüssel auf den Nutzer aus Tabelle1. Ein Nutzer, der nix macht, taucht dort nicht auf. Auch solltest Du versuchen, weitestgehend zu normalisieren. (Optimierungen mit lookup tables würde ich erst machen, wenn das Problem als Flaschenhals identifiziert wurde.)
Über die Anzahl der Reihen in einer Tabelle musst Du Dir zunächst keine Sorgen machen, solange Du Indices nutzt und die Anfragen nicht böse verschachtelte JOINs, Subselects oder UNIONs sind. Diese sind sehr RAM-hungrig, wenn die DB auslagern muss, wird das zum Performancekiller. UNIONs führen zusätzlich zu Problemen mit den Indices, was dann Rechenzeit kostet.
Das weitere Vorgehen mit den alten Daten in der Bewegungstabelle würde ich vom use case abhängig machen. Brauchst Du die nicht mehr - löschen. Sind die Zugriffe darauf selten, lohnt das Wegschreiben in ein Archiv. Falls der Server sich nachts langweilt, ist das ein guter Zeitpunkt hierfür usw.
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

Die Unterteilung werde ich in Stammdaten und Bewegungsdaten machen. Wobei sich die Stammdaten nicht ändern lassen, wie z.B. die Userid und Registrierungsdatum und Bewegungsdaten, die sich nicht nur ändern lassen, sondern auch werden.
Der Zugriff auf die Bewegungsprofile wird per Userid und Timestamp erfolgen und keine UNIONs erhalten. Da es sich um Userstatistiken handelt, werden diese nicht gelöscht. Der Transfer auf eine Archiv Datenbank bzw. Tabelle könnte sich nach einem gewissen Zeitraum lohnen, da die Standardeinstellung für die durch die Daten erzeugten Diagramme auf 30 Tage festgelegt wird.

Danke für den Einwand. :)
Antworten