Fragen zum Datenbank-Design

Injector

Neuer Benutzer
Beiträge
3
Hallo zusammen,

ich habe eine MySQL-Datenbank entworfen, um Verträge zu verwalten. Dabei habe ich mich natürlich an die Regeln der Normalisierung gehalten. Bei einigen Design-Entscheidungen bin ich mir aber nicht ganz sicher, ob man das nicht auch anders machen könnte. Daher würde ich mich über Eure Meinung zu ein paar grundsätzlichen Design-Fragen freuen...

Nummerierte Spalten:
Ich weiß, dass nummerierte Spalten normalerweise auf ein fehlerhaftes Design hindeuten, also wie z.B. Email1, Email2, Email3, etc.
Aber gibt es Ausnahmen, wo man derartige Konstrukte aus Gründen der Übersichtlichkeit und Einfachheit trotzdem anwendet? Als Beispiel seien hier z.B. 4 Boolean-Spalten genannt, die quasi eine Kunden-Checkliste in der Kundenmaske darstellen. Bei allen Kunden sind die Booleans anfangs False und werden nach und nach manuell auf True gesetzt. Die Anzahl der Spalten wird sich aufgrund eines gut etablierten Arbeits-Konzeptes auf absehbare Zeit auch nicht ändern(hört hört!!!) Gibt es hier einen gewissen Spielraum, innerhalb dessen man von den Normalisierungsregeln hätte abweichen dürfen, oder sollte man so etwas ohne Ausnahme niemals machen?

Zukünftige Vertragsänderungen:
Zukünftige Vertragsänderungen(z.B. Beitragshöhe, Zahlungsart, etc.). realisiere ich momentan über ausgelagerte Verlaufs-Tabellen. Die Beitragshöhen werden beispielsweise nicht in der Vertrags-Tabelle gespeichert, sondern zusammen mit einem Startdatum in einer separaten Beitrags-Tabelle für alle Kunden.
Auf diese Weise lassen sich auch zukünftige Vertragsänderungen planen, indem zusätzlich zum vom Datum her aktuell gültigen Wert ein weiterer Wert mit zukünftigem Startdatum gespeichert wird.
Wenn man davon ausgeht, dass man für jeden Vertragsparameter definitiv nie mehr als 2 Zustände gleichzeitig(Aktuell und Zukünftig) pro Vertrag zulassen möchte, wäre es dann denkbar, die notwendigen Felder einfach über mehrere Spalten(BeitragAktuell, BeitragZukuenftig, StartdatumBeitragZukuenftig) zu regeln? Dann müsste man nicht jedes mal mit Datumsfunktionen herumwurschteln, um die aktuellen und zukünftigen Konditionen zu ermitteln. Auf der anderen Seite müsste man dann aber wohl vor der Benutzung der Datenbank sicherstellen, dass für den aktuellen Tag die jeweils gültig gewordenen Vertragsänderungen in die Spalte "BeitragAktuell" verschoben werden und "StartdatumBeitragZukuenftig" gelöscht wird.

Speichern von Ausprägungen anstelle von Fremdschlüsseln:
Beim Anlegen der Verträge greife ich häufig auf Listen mit vorgegebenen Einträgen zurück, die in dafür angelegten Tabellen gespeichert werden. Die Einträge der einzelnen Dropdowns werden dabei immer wieder mal geändert/gelöscht/erweitert. Daher kann man diese über entsprechende Interfaces im BackEnd administrieren. Dabei ergibt sich das Problem, dass die Tabellen mit den Einträgen nicht einfach geändert oder gelöscht werden dürfen, da sonst die über Fremdschlüssel verknüpften Inhalte bereits angelegter Verträge nicht mehr stimmen würden.
Sollte man bei den Tabellen mit den vorgegebenen Einträgen grundsätzlich nur das Hinzufügen von Einträgen zulassen und das Löschen von Einträgen durch eine Boolean-Spalte(Aktiv/Inaktiv) ersetzen und bei Änderungen einfach den alten Wert inaktiv setzen und einen neuen aktiven erstellen? Oder sollte man besser gleich die Inhalte selbst an Stelle der Fremdschlüssel im Vertrag speichern, weil dann die Auswahl unabhängig von den bereits vorhandenen Verträgen jederzeit geändert/ergänzt/reduziert werden kann?

Die letzte Frage lässt sich auch auf das Erzeugen von Rechnungen übertragen. Hier würde ich aus Gründen der Dokumentations-Sicherheit noch viel mehr dazu tendieren, statische Daten anstelle der Fremdschlüssel zu speichern. Eventuell kann ja jemand diese Fragestellung auch im Hinblick auf Rechnungen beantworten.

Ich hoffe, das war jetzt nicht zu viel Text und bedanke mich schon mal fürs Lesen.

Viele Grüße
Injector
 
Werbung:
Nummerierte Spalten:
Ich weiß, dass nummerierte Spalten normalerweise auf ein fehlerhaftes Design hindeuten, also wie z.B. Email1, Email2, Email3, etc.
Aber gibt es Ausnahmen, wo man derartige Konstrukte aus Gründen der Übersichtlichkeit und Einfachheit trotzdem anwendet? Als Beispiel seien hier z.B. 4 Boolean-Spalten genannt, die quasi eine Kunden-Checkliste in der Kundenmaske darstellen. Bei allen Kunden sind die Booleans anfangs False und werden nach und nach manuell auf True gesetzt. Die Anzahl der Spalten wird sich aufgrund eines gut etablierten Arbeits-Konzeptes auf absehbare Zeit auch nicht ändern(hört hört!!!) Gibt es hier einen gewissen Spielraum, innerhalb dessen man von den Normalisierungsregeln hätte abweichen dürfen, oder sollte man so etwas ohne Ausnahme niemals machen?
was spricht dagegen, die Spalten sinnvoller zu benennen? Also jedem Check einen gescheiten Namen zu geben - und auch den Spalten?


Zukünftige Vertragsänderungen:
Zukünftige Vertragsänderungen(z.B. Beitragshöhe, Zahlungsart, etc.). realisiere ich momentan über ausgelagerte Verlaufs-Tabellen. Die Beitragshöhen werden beispielsweise nicht in der Vertrags-Tabelle gespeichert, sondern zusammen mit einem Startdatum in einer separaten Beitrags-Tabelle für alle Kunden.
Auf diese Weise lassen sich auch zukünftige Vertragsänderungen planen, indem zusätzlich zum vom Datum her aktuell gültigen Wert ein weiterer Wert mit zukünftigem Startdatum gespeichert wird.
Wenn man davon ausgeht, dass man für jeden Vertragsparameter definitiv nie mehr als 2 Zustände gleichzeitig(Aktuell und Zukünftig) pro Vertrag zulassen möchte, wäre es dann denkbar, die notwendigen Felder einfach über mehrere Spalten(BeitragAktuell, BeitragZukuenftig, StartdatumBeitragZukuenftig) zu regeln? Dann müsste man nicht jedes mal mit Datumsfunktionen herumwurschteln, um die aktuellen und zukünftigen Konditionen zu ermitteln. Auf der anderen Seite müsste man dann aber wohl vor der Benutzung der Datenbank sicherstellen, dass für den aktuellen Tag die jeweils gültig gewordenen Vertragsänderungen in die Spalte "BeitragAktuell" verschoben werden und "StartdatumBeitragZukuenftig" gelöscht wird.

Was passiert, wenn es weitere Änderungen gibt? Hier würde ich mit DATERANGE (oder TSRANGE) arbeiten, und einem passenden Constraint. Oder aber mit 2 Spalten von und bis. In MySQL geht es ja nicht besser, und auch keine Constraints möglich.


Speichern von Ausprägungen anstelle von Fremdschlüsseln:
Beim Anlegen der Verträge greife ich häufig auf Listen mit vorgegebenen Einträgen zurück, die in dafür angelegten Tabellen gespeichert werden. Die Einträge der einzelnen Dropdowns werden dabei immer wieder mal geändert/gelöscht/erweitert. Daher kann man diese über entsprechende Interfaces im BackEnd administrieren. Dabei ergibt sich das Problem, dass die Tabellen mit den Einträgen nicht einfach geändert oder gelöscht werden dürfen, da sonst die über Fremdschlüssel verknüpften Inhalte bereits angelegter Verträge nicht mehr stimmen würden.
Sollte man bei den Tabellen mit den vorgegebenen Einträgen grundsätzlich nur das Hinzufügen von Einträgen zulassen und das Löschen von Einträgen durch eine Boolean-Spalte(Aktiv/Inaktiv) ersetzen und bei Änderungen einfach den alten Wert inaktiv setzen und einen neuen aktiven erstellen? Oder sollte man besser gleich die Inhalte selbst an Stelle der Fremdschlüssel im Vertrag speichern, weil dann die Auswahl unabhängig von den bereits vorhandenen Verträgen jederzeit geändert/ergänzt/reduziert werden kann?

Die letzte Frage lässt sich auch auf das Erzeugen von Rechnungen übertragen. Hier würde ich aus Gründen der Dokumentations-Sicherheit noch viel mehr dazu tendieren, statische Daten anstelle der Fremdschlüssel zu speichern. Eventuell kann ja jemand diese Fragestellung auch im Hinblick auf Rechnungen beantworten.

das kann im Sinne der Dokumentensicherheit durchaus Sinn machen.
 
was spricht dagegen, die Spalten sinnvoller zu benennen? Also jedem Check einen gescheiten Namen zu geben - und auch den Spalten?
Aus meiner Sicht erstmal nichts. Allerdings kann die Checkliste z.B. auch einfach nur die sequenzielle Abfolge von Kundenkontakten abbilden, also ob diese bereits stattgefunden haben oder nicht. Von daher wäre eine profane Durchnummerierung naheliegend. Aber selbst wenn die Spalten völlig unterschiedliche Vorgänge abbilden würden - stünde aufgrund des gemeinsamen Datentyps nicht die Frage im Raum, ob man diese Spalten besser durch eine Tabelle mit ID, Vorgangsbezeichnung(TEXT) und Status(BOOL) abbilden würde?

Was passiert, wenn es weitere Änderungen gibt? Hier würde ich mit DATERANGE (oder TSRANGE) arbeiten, und einem passenden Constraint. Oder aber mit 2 Spalten von und bis. In MySQL geht es ja nicht besser, und auch keine Constraints möglich.

Ich hatte für mich überlegt, dass mehr als eine geplante Änderung pro Vertragseigenschaft eigentlich nicht wünschenswert ist. Zudem wollte ich auch den laufenden Monat nicht änderbar machen. Die Datenbank soll ab Anfang des nachfolgenden Monats immer nur eine zukünftige Änderung pro Vertragseigenschaft berücksichtigen. Sobald die Änderung in Kraft getreten ist, kann eine neue Änderung geplant werden. Natürlich kann man diese geplante Änderung korrigieren oder löschen, so lange sie noch nicht in Kraft getreten ist.
Diese Entscheidung hängt vornehmlich mit der Planung der Kundenmaske zusammen, wo ich bestimmte Daten so übersichtlich und unmissverständlich wie möglich angezeigt möchte. Ich habe schon darüber nachgedacht, wie oft es wohl vorkommt, dass jemand für Monat 08 die Kontoverbindung x angibt, und dann einen Tag später bereits für Monat 09 die Kontoverbindung y angeben möchte. Kommt das Deiner Erfahrung nach so häufig vor, dass man es zu Lasten der Übersichtlichkeit berücksichtigen sollte?

das kann im Sinne der Dokumentensicherheit durchaus Sinn machen.

Ok. Das dürfte dann aber je nach Inhalt ungleich mehr Speicher kosten, richtig? Kann man irgendwie abschätzen, ab wann der Speicherbedarf zum Problem werden könnte?

Vielen Dank,
Injector
 
Ich hatte für mich überlegt, dass mehr als eine geplante Änderung pro Vertragseigenschaft eigentlich nicht wünschenswert ist. Zudem wollte ich auch den laufenden Monat nicht änderbar machen. Die Datenbank soll ab Anfang des nachfolgenden Monats immer nur eine zukünftige Änderung pro Vertragseigenschaft berücksichtigen. Sobald die Änderung in Kraft getreten ist, kann eine neue Änderung geplant werden. Natürlich kann man diese geplante Änderung korrigieren oder löschen, so lange sie noch nicht in Kraft getreten ist.
Diese Entscheidung hängt vornehmlich mit der Planung der Kundenmaske zusammen, wo ich bestimmte Daten so übersichtlich und unmissverständlich wie möglich angezeigt möchte. Ich habe schon darüber nachgedacht, wie oft es wohl vorkommt, dass jemand für Monat 08 die Kontoverbindung x angibt, und dann einen Tag später bereits für Monat 09 die Kontoverbindung y angeben möchte. Kommt das Deiner Erfahrung nach so häufig vor, dass man es zu Lasten der Übersichtlichkeit berücksichtigen sollte?

Ich dachte eher an mehrere Änderungen, also eine Historie. Also etwa so:

Code:
test=*# create table preise (id int, valid daterange, preis numeric, exclude using gist (id with =, valid with &&));
CREATE TABLE
test=*# insert into preise values (1, '[2016-01-01,2016-02-28)', 10);
INSERT 0 1
test=*# insert into preise values (1, '[2016-03-01,2016-04-30)', 15);
INSERT 0 1
test=*# insert into preise values (1, '[2016-07-01,2016-07-31)', 20);
INSERT 0 1
test=*# insert into preise values (1, '[2016-08-01,)', 25);
INSERT 0 1

Hier kannst Du schön sehen, wann welcher Preis valide war. Zum Beispiel am 15. März:

Code:
test=*# select preis from preise where id = 1 and valid @> '2016-03-15'::date;
 preis
-------
  15
(1 Zeile)

Diese Suche wird auch Dank des GiST-Indexes schnell sein.

Der Constraint verhindert Überschneidungen:

Code:
test=*# insert into preise values (1, '[2016-09-01,)', 30);
ERROR:  conflicting key value violates exclusion constraint "preise_id_valid_excl"
DETAIL:  Key (id, valid)=(1, [2016-09-01,)) conflicts with existing key (id, valid)=(1, [2016-08-01,)).



Ok. Das dürfte dann aber je nach Inhalt ungleich mehr Speicher kosten, richtig? Kann man irgendwie abschätzen, ab wann der Speicherbedarf zum Problem werden könnte?

Vielen Dank,
Injector

Schwer. Du wirst ja wohl nicht anstelle einer ID dann gleich ein mehrere Terrabyte großes Binary da speichern, oder? Aber ich würde das wirklich auf Dinge begrenzen, die quasi 'eingefroren' werden sollen. Wie z.B. Rechnungen.
 
Werbung:
Ich dachte eher an mehrere Änderungen, also eine Historie.

Ok, eine Historie ist unabhäng von der Kundenmaske in der Tat eine gute Idee. Ich kann ja trotzdem einfach die zukünftigen Einträge auf maximal Einen beschränken. Die Prüfung wegen der Überschneidung muss ich ja sowieso einprogrammieren.

Binaries speichere ich keine, aber Dein Beispiel verstehe ich mal so, dass ich wohl kaum genug Kunden bekommen werde, damit die Datenbank-Performance aufgrund der relativ kurzen Strings in den Keller geht.

Vielen Dank für Deine Hilfe, ich werde die neuen Aspekte in die Datenbank einfließen lassen.

Viele Grüße
Injector
 
Zurück
Oben