# Dynamische Tabelle



## neoexpert (22. Okt 2016)

Guten Abend.
Bei Relationalen Datenbanken hat man ja starre Tabellen-Struktur. Solche Datenbanken sind damit ja weniger "skalierbar".
Ich habe einen interessanten Ansatz gewählt um dem zu entgehen:
Eine Tabelle (Mit recursiver Struktur) die Folgende Form hat:
ID INT, NAME VARCHAR, PARENT_ID INT, TYPE VARCHAR, VALUE _ID INT
ID ist primary Key und PARENT_ID zeigt auf eine Zeile aus der selben Tabelle.
Dann gibt es für jeden Wert von "TYPE" eine Tabelle in der die jeweigen Werte gespeichert werden.
Für TYPE "INT" z.B.
ID INT, VALUE INT
für TYPE "STRING"
ID INT, VALUE TEXT
Und so für jeden TYPE.

Nun kann man in diese Tabelle beliebige Objekte speichern. Ist das effizient?
Es ist beliebig skalierbar und man braucht überhaupt keine anderen Tabellen mehr.


----------



## stg (22. Okt 2016)

neoexpert hat gesagt.:


> Ist das effizient?



Nein. Denke im einfachsten Fall schon an die Zahlreichen JOINs, die du durchführen musst, um einfache Datensätze abzufragen. Von komplexeren Strukturen oder Auswertungen ganz zu schweigen.

Du schränkst dich auch unnötig ein, was die Unterstützung seitens der Datenbank z.B. hinsichtlich Datenintegrität anbetrifft.

Für gewöhnlich kennt man die Daten (und die Struktur der Daten), die man speichern will, da ist das Design der Datenbank einmalige Arbeit.
Natürlich fällt Arbeit an, wenn es Änderungen am Datenmodel gibt, das persistiert werden soll, aber die hast du dann bei deinem Model zwangsläufig doppelt und dreifach im Programmcode.

Den Begriff "Skalierbarkeit" solltest du auch noch einmal nachschlagen.

Relationale Datenbank haben sich sehr bewährt, sind aber auch nicht das Non-Plus-Ultra. Eine Alternative können etwa  Objekt-Datenbanken oder Mischformen darstellen. Auch unterstützen einige Datenbanken, dass du "Objekte" im JSON Format vorhalten kannst. Was das richtige ist, muss man immer individuell entscheiden.


----------



## neoexpert (23. Okt 2016)

Ich habe ausgerechnet: hätte man für jeden Atom im Universum (nehmen wir mal an es wären 2^1000) einen Datensatz in unserer Tabelle, dann würde man anhand des Schlüssels (sagen wir mal ein Integer) nur 1000 vergleiche benötigen um auf den entsprechenden Datensatz zu kommen. Sicherlich in weniger als einer Millisekunde.


----------



## mrBrown (23. Okt 2016)

Einen Datensatz finden ist jetzt auch nicht so sonderlich schwer und um 2^1000 Simple Datensätze zu speichern, braucht man nicht deine ... interessante Struktur


----------



## neoexpert (24. Okt 2016)

Trotzdem damit programmiere ich einen abstrakten Shop. Und das wird sicher perfomant genug sein. Übrigens: wenn die Physiker recht damit haben, dass das Universum endlich ist wird man 2^1000 Datensätze niemals speichern können. Es gibt nicht genug Elementarteilen.


----------



## stg (24. Okt 2016)

neoexpert hat gesagt.:


> Trotzdem damit programmiere ich einen abstrakten Shop.


Viel Spaß.



> Und das wird sicher perfomant genug sein.


Kommt halt ganz drauf an, was man unter "genug" versteht bzw was gefordert wird.

Du kannst das ja gerne so machen. Ich würd's nicht tun. Auf Probleme wirst du möglicherweise auch erst stoßen, wenn du etwas "interessantere" Fälle betrachtest. Du kannst ja mal berichten, sobald du etwas brauchbares zu Stande gebracht hast...


----------



## Meniskusschaden (24. Okt 2016)

Wenn die Datenmenge klein genug bleibt, tritt vielleicht wirklich kein Performanceproblem in Erscheinung. Aber für den Entwickler wird das ein Albtraum. Man muß seine Daten doch trotzdem strukturieren, wirft aber die schönen Strukturierungsmöglichkeiten weg, die einem die Datenbank schenkt. Zusätzlich verzichtet man auch auf sämtliche Werkzeuge wie Berichtsgeneratoren usw.. Wie soll man die Daten denn auswerten?

Bilde doch mal testweise eine Bestellung damit ab und vergleiche sie mit der herkömmlichen Struktur. Es genügt ja das Pendant zu einem ganz schlichten System, bestehend aus den Tabellen Kunde, Artikel, Bestellung und Bestellposition. Schon bei dem Gedanken, das in deine Tabellen zu überführen wird mir schwindlig.


----------



## sascha-sphw (25. Okt 2016)

Ich kann mich meinen Vorrednern nur anschließen, wenn Du in Deiner Struktur mal einen Fehler suchen musst, ist der Vorteil den Du Dir versprichst dahin.
Lieber überlege ich mir vorher welche Teile der DB überhaupt dynamisch sein müssen. Die Tabelle Kunde, Bestellung, Produkt, usw. werden sich nur Bedingt ändern. Dann lieber nur für z.B. Produkt_Meta einen dynamischen Part mit Key/Value einbauen den man dann auch entsprechend zu visualisieren weiß. 

Letzten Endes muss man immer wissen wo und wie Daten angezeigt werden und damit weiß ich, meiner Meinung nach, auch welche Daten das sind.


----------



## JStein52 (25. Okt 2016)

neoexpert hat gesagt.:


> Solche Datenbanken sind damit ja weniger "skalierbar".


Was soll das eigentlich heissen ? Denn das ist ja scheinbar der Ausgangspunkt deiner abstrusen Überlegungen.


----------



## neoexpert (25. Okt 2016)

http://62.214.160.146:8080
Das ist so eine vor-alpha version. Jeder der sich anmeldet ist admin.
unter /admin kann man verwalten. Inetessant ist die Vererbung: Atributte im root werden von allen Entitäten vererbt. Man muss selbst die Beschreibung und auch Bild selber definieren. Nach dem Motto: diefiniere dein Shop doch selber.
Auf Mobilen Geräten habe ich das menü noch nicht implementiert: also admin geht besser auf grösserem Bildschirm.

Übrigens: nur eine Tabelle, auch Benutzer und Bestellingen, alles ist in der Suppe drin.
Finde ich übersichtlicher als jede menge Tabellen.


----------



## JuKu (25. Okt 2016)

neoexpert hat gesagt.:


> Guten Abend.
> Bei Relationalen Datenbanken hat man ja starre Tabellen-Struktur. Solche Datenbanken sind damit ja weniger "skalierbar".
> Nun kann man in diese Tabelle beliebige Objekte speichern. Ist das effizient?
> Es ist beliebig skalierbar und man braucht überhaupt keine anderen Tabellen mehr.



Solche Dynamik ist immer teuer, was die Performance angeht.
Jedes unnötige SELECT Statement oder jedes JOIN kostet Performance, gerade bei MySQL.


----------



## JStein52 (25. Okt 2016)

Und wo in deiner Suppe merkst du dir nun den Aufbau einer Bestellung ? Eines Kunden ? Eines Artikels ? Usw. Und was genau ist der Vorteil den du da siehst Wenn du die Daten einer Bestellung auf etwa 8-10 Tabellen verteilst statt auf eine ?


----------



## neoexpert (25. Okt 2016)

Jede Bestellung wird in der Categorie Order gepackt: also parent_id von jeder Bestellung ist gleich der id von der Kategorie Order


----------



## sascha-sphw (25. Okt 2016)

@neoexpert Mir kommt es so vor als ob Dich die Meinung der Leute überhaupt nicht interessiert, da Du Deine Version so hartnäckig verteidigst und offensichtlich auch, entgegen der vorherrschenden Meinung, gut findest. Da frag ich mich warum Du überhaupt gefragt hast.


----------



## Thallius (25. Okt 2016)

Also entweder ich habe es überhaupt nicht kapiert oder das ganze ist vollkommener Quatsch.

Nehmen wir mal an ich suche alle Bestellungen in denen ein Artikel der Firma Y enthalten ist. Dann muss ich also zunächst man alle Tabellen Einträge suchen deren Type Artikel ist. Dann muss ich davon alle Einträge suchen deren Parent ID vom Type Bestellung ist damit ich weis das es auch ein Artikel aus einer Bestellung ist und nicht z.B. Eine Artikel aus dem Lager ist. Dann musss ich alle Einträge suchen vom Type Hersteller ist und deren parent ID gleich meinem Artikel ist und deren Wert y ist?.. 

Sorry aber da kapier ich ja selbst beim aufschreiben kaum noch.

Claus


----------



## JStein52 (25. Okt 2016)

neoexpert hat gesagt.:


> also parent_id von jeder Bestellung ist gleich der id von der Kategorie Order


Und woher weisst du welcher Eintrag in der Suppentabelle eine Order ist, geschweige denn welche Order das nun ist. Und anschliessend musst du dir aus den TYPE-Tabellen die Attributwerte zusammensuchen.


----------



## JStein52 (25. Okt 2016)

Thallius hat gesagt.:


> Sorry aber da kapier ich ja selbst beim aufschreiben kaum noch


Jepp, genau so !!


----------



## mrBrown (25. Okt 2016)

Hat ihm wohl schon mal jemand NoSQl-Datenbanken gezeigt?


----------



## Meniskusschaden (25. Okt 2016)

JStein52 hat gesagt.:


> Und was genau ist der Vorteil den du da siehst Wenn du die Daten einer Bestellung auf etwa 8-10 Tabellen verteilst statt auf eine ?


Man kann sich für den Quellcode den Obfuscator sparen.


----------



## neoexpert (25. Okt 2016)

sascha-sphw hat gesagt.:


> @neoexpert Mir kommt es so vor als ob Dich die Meinung der Leute überhaupt nicht interessiert, da Du Deine Version so hartnäckig verteidigst und offensichtlich auch, entgegen der vorherrschenden Meinung, gut findest. Da frag ich mich warum Du überhaupt gefragt hast.


Natürlich interessiert mich die Meinung. Z.B. hat Thallius was interessantes gesagt:


Thallius hat gesagt.:


> Also entweder ich habe es überhaupt nicht kapiert oder das ganze ist vollkommener Quatsch.
> 
> Nehmen wir mal an ich suche alle Bestellungen in denen ein Artikel der Firma Y enthalten ist. Dann muss ich also zunächst man alle Tabellen Einträge suchen deren Type Artikel ist. Dann muss ich davon alle Einträge suchen deren Parent ID vom Type Bestellung ist damit ich weis das es auch ein Artikel aus einer Bestellung ist und nicht z.B. Eine Artikel aus dem Lager ist. Dann musss ich alle Einträge suchen vom Type Hersteller ist und deren parent ID gleich meinem Artikel ist und deren Wert y ist?..
> 
> ...


Alle Bestellungen in denen ein Artikel der firma xy enthalten ist?
Man muss da natürlich in allen items suchen die bestellt wurden. Aber das ist bei relationalem fall auch nicht einfach.


mrBrown hat gesagt.:


> Hat ihm wohl schon mal jemand NoSQl-Datenbanken gezeigt?


MongoDB ist Super. Ich habe halt die vorgabe SQL zu benutzen.


----------



## neoexpert (25. Okt 2016)

JStein52 hat gesagt.:


> Und woher weisst du welcher Eintrag in der Suppentabelle eine Order ist, geschweige denn welche Order das nun ist. Und anschliessend musst du dir aus den TYPE-Tabellen die Attributwerte zusammensuchen.


Spalte "TYPE" ist beim Order gleich "ORDER"
Alle ORDER:
SELECT * FROM CATEGORIES WHERE TYPE="ORDER"


----------



## Thallius (25. Okt 2016)

neoexpert hat gesagt.:


> Alle Bestellungen in denen ein Artikel der firma xy enthalten ist?
> Man muss da natürlich in allen items suchen die bestellt wurden. Aber das ist bei relationalem fall auch nicht einfach.



Aehm doch nur mal so schnell hingerotzt...

Select ...
From Bestellungen
Join xArtikelBestellungen on xArtikelBestellungen.bestellundID = Bestellungnen.id
Join Artikel on Artikel.id = xArtikelBestellungen.ArtikelID
Join Hersteller on Hersteller.id = Artikel.HerstellerID
Where Hersteller.Name = "..... 
Group By Bestellungen.ID

Gruß

Claus


----------



## neoexpert (25. Okt 2016)

Jemand hat gerade das Attribut "Passwort" aus der Kategorie "Users" gelöscht. Nach dieser Logik kann man auch jedem Benutzer beliebige Attribute zuweisen, ohne zusätzliche Spalten hinzuzufügen


----------



## neoexpert (25. Okt 2016)

Später packe ich die Benutzer in unterkategorien um so z.B. die Benutzer zu gruppieren und zu berechten.


----------



## JStein52 (25. Okt 2016)

Ich verstehe deine Tabellen gerade überhaupt nicht. Jetzt gibt es also doch eine Tabelle namens "ORDER" ?


neoexpert hat gesagt.:


> Dann gibt es für jeden Wert von "TYPE" eine Tabelle in der die jeweigen Werte gespeichert werden


???


----------



## neoexpert (25. Okt 2016)

Also das mit extra Tabellen habe ich bei dem Shop erstmal nicht gemacht. Ich verwende einfach Strings für jeden typ. Erstmal. Also ich habe tatsächlich nur eine Tabelle.


----------



## JStein52 (25. Okt 2016)

neoexpert hat gesagt.:


> Also ich habe tatsächlich nur eine Tabelle.


Du machst mich meschugge. Eine Tabelle kann ja auch wieder nicht sein. Wie ist die denn aufgebaut ?
doch bestimmt nicht so:


neoexpert hat gesagt.:


> Eine Tabelle (Mit recursiver Struktur) die Folgende Form hat:
> ID INT, NAME VARCHAR, PARENT_ID INT, TYPE VARCHAR, VALUE _ID INT
> ID ist primary Key und PARENT_ID zeigt auf eine Zeile aus der selben Tabelle.


----------



## neoexpert (25. Okt 2016)

Beispiel:


JStein52 hat gesagt.:


> Du machst mich meschugge. Eine Tabelle kann ja auch wieder nicht sein. Wie ist die denn aufgebaut ?
> doch bestimmt nicht so:


ID INT, NAME VARCHAR(256), PARENT_ID INT, TYPE VARCHAR, VALUE TEXT
So habe ich das zur Zeit. Das ist im Prinzip eine Baumstruktur (kann man aufmalen)


----------



## JStein52 (25. Okt 2016)

Und was hat diese Tabelle mit einer Bestellung zu tun ?


----------



## neoexpert (25. Okt 2016)

Bestellung würde so aussehen
ID,   NAME, PARENT_ID, TYPE,      VALUE
42, ""           41,                 "ORDER",   ""
Name und Value nicht Notwendig
Items sehen so aus:
ID,   NAME, PARENT_ID, TYPE,   VALUE
43, ""           42,                 "ITEM",     ""
44, ""           42,                 "ITEM",     ""

...


----------



## JStein52 (25. Okt 2016)

Und wo steht das Bestelldatum ? Das Lieferdatum ?

Edit: der Preis ? usw.


----------



## neoexpert (25. Okt 2016)

Der Shop ist gerade leider nicht nutzbar: zu viele admins. Korrigiere ich Morgen


----------



## neoexpert (25. Okt 2016)

JStein52 hat gesagt.:


> Und wo steht das Bestelldatum ? Das Lieferdatum ?
> 
> Edit: der Preis ? usw.


Hier:
ID, NAME, PARENT_ID, TYPE, VALUE
43, "Lieferdatum" 42, "ATTRIBUTE", "12.12.2017"
Man sieht an PARENT_ID, dass es zu dem Order 42 gehört


----------



## JStein52 (25. Okt 2016)

Aber das Datum ist eben kein DATE, der Preis kein DECIMAL, Wenn du alle Bestellungen eines bestimmten Zeitraumes suchst wirst du ja wahnsinnig. Positionsgrössen, einzelpreise, Summenpreis etc. musst du ja lles selber codieren. Das ist ja die Hölle


----------



## neoexpert (25. Okt 2016)

JStein52 hat gesagt.:


> Aber das Datum ist eben kein DATE, der Preis kein DECIMAL, Wenn du alle Bestellungen eines bestimmten Zeitraumes suchst wirst du ja wahnsinnig. Positionsgrössen, einzelpreise, Summenpreis etc. musst du ja lles selber codieren. Das ist ja die Hölle


Ja die primitiven Datentypen speichere ich eventuell in separaten Tabellen. Für jeden Primitiven TYPE extra Tabelle. Aber es gibt ja nur folgende: int, long, float, double
Und eine tabelle für Strings. Mehr braucht man nicht. DATE ist long.
Edit: vllt noch boolean.


----------



## Meniskusschaden (25. Okt 2016)

neoexpert hat gesagt.:


> Bestellung würde so aussehen
> ID, NAME, PARENT_ID, TYPE, VALUE
> 42, "" 41, "ORDER", ""
> Name und Value nicht Notwendig
> ...


Wie geht es dann weiter? Vielleicht so:

```
ID   NAME   PARENT_ID   TYPE     VALUE
42          41          ORDER    BE-001   // Bestellung
43          42          ITEM     10       // erste Position
44          42          ITEM     20       // zweite Position
45          43          ARTICLE  4711     // Postitionsdaten
46          43          AMOUNT   7        //   zur ersten
47          43          PRICE    1.99     //   Position
48          44          ARTICLE  4712     // Positionsdaten
49          44          AMOUNT   5        //   zur zweiten
50          44          PRICE    1.78     //   Position
```
Schon eine einfache Aufgabe, wie etwa die Positionsdaten einer Bestellung anhand ihrer Bestellnummer zeilenweise auszugeben, wird  ganz schön mühselig.



JStein52 hat gesagt.:


> Und wo steht das Bestelldatum ? Das Lieferdatum ?
> 
> Edit: der Preis ? usw.


Im Grunde bildet er wohl "virtuelle Tabellen" in einer nornalen Tabelle ab. Er muß also alle Verwaltungsfunktionen nachbauen. Das könnte schon funktionieren. Man muß eben nur auf Komfort und Performance verzichten.


----------



## neoexpert (26. Okt 2016)

Meniskusschaden hat gesagt.:


> Schon eine einfache Aufgabe, wie etwa die Positionsdaten einer Bestellung anhand ihrer Bestellnummer zeilenweise auszugeben, wird  ganz schön mühselig.


Naja da habe ich eine Klasse "Attribute" die hat so Methoden wie "getType()" "getValue()"
Und z.B. eine Klasse Category mit methoden "getAttribute(String)" usw.
Alles ist eine Kategorie.
So ähnlich wie "Alles ist eine Datei"


----------



## neoexpert (26. Okt 2016)

Ausserdem gibt es spezifischere klassen wie
class User extends Category
...


----------



## neoexpert (26. Okt 2016)

Man kann das ganze sogar so weit vereinfachen, dass man Beliebige java Objecte speichern kann die Serializable sind. Ich glaube solche Lösungen gibt es bereits.


----------



## Meniskusschaden (26. Okt 2016)

neoexpert hat gesagt.:


> Naja da habe ich eine Klasse "Attribute" die hat so Methoden wie "getType()" "getValue()"
> Und z.B. eine Klasse Category mit methoden "getAttribute(String)" usw.


Das ändert aber nichts daran, dass du pro Spalte deiner Ergebnismenge mindestens einen JOIN benötigst, wohingegen du beim herkömmlichen Ansatz in der Regel nur einen pro beteiligter Tabelle brauchst. Für eine komplette Anwendung ist das kaum praktikabel. Für Teilbereiche kann man aber so arbeiten. Beispielsweise werden frei konfigurierbare Sachmerkmale in ERP-Systemen oft ähnlich realisiert.


----------



## Tobse (26. Okt 2016)

neoexpert hat gesagt.:


> Ich glaube solche Lösungen gibt es bereits.


Hibernate + ein DB-Migrationstool deiner Wahl. Das kannst du von release zu release ändern, was du willst. Und Performanter ist es allemal.

Wenn deine Idee so toll ist, arbeite sie doch zu Ende aus und präsentiere sie uns in einer Verständlichen Form. Hier nach Meinungen zu Fragen und dann die Aussgen anderer mit Dingen wie "ist ein einer relationalen DB aber auch nicht einfach" abzuschmettern ist höchstens peinlich.
Wenn du die Vorgabe SQL hast und versuchst, sie auf diese Weise zu umgehen, kann ich die Bewertung "Thema Verfehlt" schon vor mir sehen.


----------



## JuKu (26. Okt 2016)

Was du also willst, ist, dass du dynamisch Spalten hinzufügen kannst.
Dafür ist MySQL aber nicht gedacht, für sowas gibts NoSQL Datenbanken wie Cassandra.
MySQL ist eine relationale Datenbank, d.h. es ist nicht dessen Stärke ne NoSQL Datenbank zu simulieren (was du gerade versuchst), weil das extrem lahm wird, sondern die Daten geordnet (mit Struktur) abzuspeichern.


----------



## neoexpert (26. Okt 2016)

Ich habe auch ganz Normal angefangen: erstmal Benutzer-Verwaltung (Extra Tabelle für Benutzer) Produkte-Verwaltumg, habe sogar eine Bilder-Gallerie gemacht mit zusätzlicher Tabelle. Und habe immer gemerkt, dass die dinger sich wiederholen:
Man muss für das Löschen eines Elements (Bild, Produkt, Benutzer) eigene Routine schreiben, da alle Tabellen anders sind.
In dem Shop ist es praktisch die Produkte zu Kategorisieren. So machte ich auf ähnliche weise eine extra Tabelle für Kategorien. Und dann ist mir die Baumstruktur aufgefallen: Man kann in so einen Baum alles Speichern.
Dann wollte ich auch Attribute beliebig definieren können, so dass sich die Produkte Ihre Kategorienattribute vererben (In der Kategorie "Monitore" soll jedes element "Bildschirmauflösung" haben.


----------



## neoexpert (26. Okt 2016)

JuKu hat gesagt.:


> Was du also willst, ist, dass du dynamisch Spalten hinzufügen kannst.
> Dafür ist MySQL aber nicht gedacht, für sowas gibts NoSQL Datenbanken wie Cassandra.
> MySQL ist eine relationale Datenbank, d.h. es ist nicht dessen Stärke ne NoSQL Datenbank zu simulieren (was du gerade versuchst), weil das extrem lahm wird, sondern die Daten geordnet (mit Struktur) abzuspeichern.


Naja MySQL liefert ja diese wunderbare B-Baum-Struktur. Und wie gesagt: der plan war typisch mysql mit gewöhnlichem Datenmodel.


----------



## neoexpert (26. Okt 2016)

*Übrigens man sollte besser Maria DB nutzen. Oracle hat ja MySQL gekauft. Man muss sich auf Verschlechterungen freuen.


----------



## sascha-sphw (26. Okt 2016)

Ich verstehe den Grund für Deinen Beitrag leider immer noch nicht. Zu jedem validen Argument gegen Deine Struktur kommt von Dir ein vernichten "Gutes" Gegenargument.
Du eliminierst "vernünftigerweise" jegliche Hilfe der DB, frei nach dem Motto "Wenn was gut werden muss, mach es selbst!".
Du hast absolut valide und nachvollziehbare Vererbungshierarchien (User extends Category).
Die DB Struktur ist auf den ersten Blick verstanden womit im späteren Fehlerfall die Bugfixing Zeit auf ein Minimum reduziert wird.
All diese Optimierung für eine unnötige Dynamik auf Kosten der Übersichtlichkeit und Performance. Das nenne ich mal einen "Fairen Deal!".
Zudem nutzt Du die Kritik anderer um Deine Argumentation zu verbessern. Du hast mich bereits überzeugt, ich werde im nächsten Projekt "sicherlich" Deinen Weg präferieren.
Also für mich sieht es so aus als hättest Du alles im Griff!

Ist das so in etwa das was Du hören möchtest?
Ich würde sagen, gehe Deinen Weg so wie Du ihn für Richtig hältst. Wenn er für Dich funktioniert.

Anschließend nochmal die konkrete Antwort auf Deine Frage.


> Ist das effizient?


NEIN!


----------



## neoexpert (26. Okt 2016)

sascha-sphw hat gesagt.:


> Ichverstehe den Grund für Deinen Beitrag leider immer noch nicht.


Erkenntnisgewinn? Eure Meinung lesen? Vllt geht diese Vorgehensweise auch komplett daneben. Muss man mal testen.


----------



## mrBrown (26. Okt 2016)

neoexpert hat gesagt.:


> Vllt geht diese Vorgehensweise auch komplett daneben


Ja, ist sie.


----------



## neoexpert (26. Okt 2016)

mrBrown hat gesagt.:


> Ja, ist sie.


Na das stimmt aber nicht. Der Shop läuft wieder.


----------



## mrBrown (26. Okt 2016)

Man könnte die ganzen Daten auch in einer großen .txt speichern und er würde trotzdem laufen...


----------



## Meniskusschaden (26. Okt 2016)

neoexpert hat gesagt.:


> Na das stimmt aber nicht. Der Shop läuft wieder.


Es bezweifelt ja auch niemand, dass man auf diese Weise ein funktionsfähiges Programm erstellen kann. Man wird nur hinsichtlich Eintwicklungsaufwand und Performance ineffizienter. Je größer die Anwendung wird, desto intensiver werden diese Probleme in Erscheinung treten. Welche Vorteile bekommt man dafür?

Ich vermute, du meinst oben mit "Skalierbarkeit" eigentlich Flexibilität hinsichtlich des Hinzufügens zusätzlicher Datenfelder und siehst darin die Vorteile. Da sollte man unterscheiden, ob es darum, dass der Entwickler oder der Anwender sie hinzufügt.

Für den Entwickler würde das bedeuten, dass er die neuen Datenfelder nicht mit den Werkzeugen des DBMS einbaut, sondern in deine Tabellenstruktur. Im ersten Fall liefert ihm das DBMS die Werkzeuge dafür, im zweiten Fall mußt du sie erst programmieren. In beiden Fällen muß er sich aber darum kümmern und spart keine Arbeit.

Wenn der Anwender die Möglichkeit bekommen soll, eigene Datenfelder zu erstellen, geht das nur über eine Tabellensteuerung, denn er hat natürlich keinen Zugriff auf die Verwaltungsfunktionen der DB. Aber das muß der Entwickler doch auch bei deinem Ansatz entsprechend vorsehen. Es muß ja irgendwo definiert werden, was mit welchen Informationen gemacht werden soll. Das ist nicht mit dem Einfügen in eine Mastertabelle erledigt.

Wie früher schon einmal erwähnt, ist das Abbilden von Sachmerkmalen oder Klassifizierungen ein Anwendungsfall, für den ähnliche Strukturen gut funktionieren. Das ist dann aber auch nur Bestandteil der Normalisierungen des normalen Relationenkonzepts.


----------



## neoexpert (26. Okt 2016)

mrBrown hat gesagt.:


> Man könnte die ganzen Daten auch in einer großen .txt speichern und er würde trotzdem laufen...


Ja dann muss man sich gute Suchalgorithmen ausdenken, was bei Maria DB schon gut gelöst ist.

Ach wisst ihr was: sollte der Shop zu langsam werden, implementiere ich ladebalken für längere vorgänge, es ist spannend zuzusehen wenn etwas passiert. Man freut sich auf so ein "Progress".
Man kann ja auch Datensätze auf  die ganz lange nicht zugegriffen wurde in eine andere Tabelle archivieren.


----------



## JuKu (26. Okt 2016)

Ich muss mich da leider Meniskusschaden anschließen.



neoexpert hat gesagt.:


> Ich habe auch ganz Normal angefangen: erstmal Benutzer-Verwaltung (Extra Tabelle für Benutzer) Produkte-Verwaltumg, habe sogar eine Bilder-Gallerie gemacht mit zusätzlicher Tabelle. Und habe immer gemerkt, dass die dinger sich wiederholen:
> Man muss für das Löschen eines Elements (Bild, Produkt, Benutzer) eigene Routine schreiben, da alle Tabellen anders sind.
> In dem Shop ist es praktisch die Produkte zu Kategorisieren. So machte ich auf ähnliche weise eine extra Tabelle für Kategorien. Und dann ist mir die Baumstruktur aufgefallen: Man kann in so einen Baum alles Speichern.
> Dann wollte ich auch Attribute beliebig definieren können, so dass sich die Produkte Ihre Kategorienattribute vererben (In der Kategorie "Monitore" soll jedes element "Bildschirmauflösung" haben.



In einer MySQL Datenbank arbeitest du nicht einfach mit "Elementen", sondern mit konkreten Spalten / Feldern.
Und natürlich ist keine Tabelle gleich, das würde auch gar keinen Sinn ergeben!
Die Tabellen sind nicht abstrakt, sondern konkret. Man kann es mit der Mathematik vergleichen, ein Mathematiker denkt sich was wunderschönes, theoretisches aus, was seiner Meinung nach super aussieht und funktionieren müsste, aber der eher praktisch orientierte Informatiker (in den meisten Unis mittlerweile Ingeneurswissenschaft) kann es fast nie 1 : 1 so implementieren - eben weil es zwar so toll aussieht, aber entweder nicht lösbar (begrenzte Rechenresourcen) oder nicht performant wäre.
In der Geschichte haben Naturwissenschaftler etwas entdeckt / erforscht, aber erst ein Ingeneur konnte das effizient nutzbar machen, z.B. bei der Dampfmaschine. Das ist eben der große Unterschied zwischen Theorie und Praxis.
Auch das Smartphone gab es schon lange, bevor Apple es "erfand", aber Apple hat es geschafft, das Smartphone so zu gestalten, dass es für den Otto-Normal-Verbraucher interessant wurde.

Nun aber genug abgeschweift, zurück zum Thema:
Für jede Tabelle eine Routine zu schreiben (ich hoffe du meinst damit keine MySQL Routine!) macht das ganze eben performant.

Wenn du folgende Tabelle hast (habs jetzt nicht validiert / getestet):

```
CREATE TABLE `test_table` (
`id` int(10) AUTO_INCREMENT,
`name` VARCHAR(600),
`prename` VARCHAR(600),
`mail`, VARCHAR(255),
PRIMARY KEY `id`,
INDEX `name`
);
```

Und du von dem Namen "neoexpert" die ID wissen willst, dann schreibst du folgenden Query:

```
SELECT * FROM `test_table` WHERE `name` = 'neoexpert';
```

MySQL sucht danach nach dem String neoexpert nur in der Spalte "name" und nicht überall (!) und liefert dir dann die ganze Zeile zurück. Da ich einen Index gesetzt habe, hat MySQL intern neben der normalen Datei noch eine Datei angelegt, wo "name - Zeilennummer" steht, sodass MySQL die Spalte "name" sehr schnell und performant suchen und finden kann.
In deinem Beispiel würde MySQL aber ebenfalls alle Einträge von "prename" und "mail" mit durchgehen müssen, da diese ja in der selben Tabelle und der selben Spalte stehen. Und genau dies ist nicht performant, da MySQL hierbei 4x so viele Daten durchsuchen müsste.

Bäume sind optimiert darauf, Werte auf genau 1 Key zu suchen - MySQL hat aber nicht nur 1 Key!
Du willst ja nicht nur die Zeile über die ID, sondern ebenfalls über die Spalte "name" direkt suchen können.
Und genau das können die meisten dokument-orientierten NoSQL Datenbanken (z.B. MongoDB) ebenfalls nicht wirklich effizient, weil es nicht deren Ziel ist! Relationen sind nicht wirklich gut skalierbar, weil sie genau deshalb so viele Abhängigkeiten besitzen, aber MySQL ist eben auch nicht für Big Data ausgelegt. Und MongoDB ist auch eher dafür ausgelegt, nach einem bestimmten Key zu suchen (sagt mir, wenn ich mich irre!), auch wenn man nach Spalten suchen kann. Wenn du einen einfachen Key-Value-Store hättest, wäre nen Baum natürlich eine der effizientesten Möglichkeiten, aber solch einen hast du hier einfach nicht.


----------



## JuKu (26. Okt 2016)

neoexpert hat gesagt.:


> Ja dann muss man sich gute Suchalgorithmen ausdenken, was bei Maria DB schon gut gelöst ist.



Suchalgorithmen sind in MariaDB / MySQL nur effizient, wenn du auf die Spalte auch nen Index gelegt hast.



neoexpert hat gesagt.:


> Ach wisst ihr was: sollte der Shop zu langsam werden, implementiere ich ladebalken für längere vorgänge, es ist spannend zuzusehen wenn etwas passiert. Man freut sich auf so ein "Progress".
> Man kann ja auch Datensätze auf  die ganz lange nicht zugegriffen wurde in eine andere Tabelle archivieren.



Früher war das vllt. noch "in", mittlerweile will der Nutzer seine Antwort am liebsten in Echtzeit, also auf deutsch: sofort.
Vorallem in der Wirtschaft (z.B. Shop) kostet sowas viel Geld und da du einen Shop bauen willst, würden die Nutzer vllt. lieber zu einem anderem Shop wechseln, weil ihnen die Suche einfach zu lange dauert. Selbst bei Amazon dauert die Suche für meinen Geschmack schon etwas zu lang, aber bei der Datenmenge, die sie durchsuchen müssen, ist das was ganz anderes.


----------



## neoexpert (26. Okt 2016)

Man kann ja in SQL auch Views definieren. Werden diese gecached? Vllt wäre das eine Möglichkeit virtuelle Tabelle zu generieren auf die dann schnell zugegriffen werden kann.


----------



## mrBrown (26. Okt 2016)

Oder einfach noch einfacher, SQL so nutzen, wie es gedacht ist


----------



## JuKu (26. Okt 2016)

mrBrown hat gesagt.:


> Oder einfach noch einfacher, SQL so nutzen, wie es gedacht ist



Genau!



neoexpert hat gesagt.:


> Man kann ja in SQL auch Views definieren. Werden diese gecached? Vllt wäre das eine Möglichkeit virtuelle Tabelle zu generieren auf die dann schnell zugegriffen werden kann.



Views sind auch nur virtuelle (vermutlich nur im RAM gehaltene?) Tabellen.
Überlass solche Optimierungen lieber MySQL selbst - die wissen (hoffentlich) schon, was sie da tun.
Außerdem kannst du dein Memory Limit in der Konfiguration so anpassen, dass MySQL von selbst Queries (Abfragen) cachet.


----------



## JStein52 (26. Okt 2016)

JuKu hat gesagt.:


> Relationen sind nicht wirklich gut skalierbar, weil sie genau deshalb so viele Abhängigkeiten besitzen


Was versteht ihr denn unterskalierbar ?


JuKu hat gesagt.:


> aber MySQL ist eben auch nicht für Big Data ausgelegt.


Du würdest dich wundern wenn du mal Statistiken siehst wo überall MySQL dahinter steckt.


----------



## Tobse (26. Okt 2016)

neoexpert hat gesagt.:


> *Übrigens man sollte besser Maria DB nutzen. Oracle hat ja MySQL gekauft. Man muss sich auf Verschlechterungen freuen.


Ich freue mich, dass ich von einem Datenbankexperten so einen Wertvollen Tipp erhalten habe!   



neoexpert hat gesagt.:


> Man muss für das Löschen eines Elements (Bild, Produkt, Benutzer) eigene Routine schreiben, da alle Tabellen anders sind.


B
Bitte was? In welcher Realität lebst du?


```
# löschen eines Datensatzes in einer normalen, relationalen DB, Löschweritergabe (On Delete Cascade) über FKs
DELETE FROM Category WHERE primaryKey = ?
```


```
// löschen eines Datensatzes in deiner Tabellenstruktur mit Löschweitergabe (On Delete Cascade)
void delete(int itemId) {
  int[] childIds = SELECT primaryKey FROM Category WHERE parentId = :itemId
  for (int childId : childIds) {
    delete(childId); // rekursion
  }
  DELETE FROM Category WHERE parentId = :itemId
  DELETE FROM Category WHERE primaryKey = :itemId
}
```

Du brauchst uns nicht erzählen, dass deine Methodik einfacher wäre. Im Gegenteil; mit deiner Methode bekommt man ekelhafte enge Bindung zwischen hardcore Logik-Code und der DB, Wartbarkeit = 0.

P.S.: Bist du ein Troll? Oder leidest du am Dunning-Kruger Effekt?


----------



## neoexpert (26. Okt 2016)

Ich


Tobse hat gesagt.:


> Ich freue mich, dass ich von einem Datenbankexperten so einen Wertvollen Tipp erhalten habe!
> 
> B
> Bitte was? In welcher Realität lebst du?
> ...


Ich fühle mich Beleidigt. Ich habe zu keinem Zeitpunkt getrollt, nur reagiert.
Ab jetzt schreibe ich nichts mehr.


----------



## mrBrown (26. Okt 2016)

Ich dagegen habe zu keinem Zeitpunkt reagiert, nur getrollt.


----------



## Tobse (26. Okt 2016)

mrBrown hat gesagt.:


> Ich dagegen habe zu keinem Zeitpunkt reagiert, nur getrollt.


mmd 

-----


neoexpert hat gesagt.:


> Ich fühle mich Beleidigt.


Das tut mir leid. Ich meins nicht wirklich böse  Aber mir geht beim besten Willen nicht in den Kopf, warum du so starrhaft versuchst, ein Problem mit einem Werkzeug zu lösen, das dafür nicht ansatzweise geschaffen ist.


----------



## Thallius (26. Okt 2016)

Tobse hat gesagt.:


> mmd
> 
> -----
> 
> Das tut mir leid. Ich meins nicht wirklich böse  Aber mir geht beim besten Willen nicht in den Kopf, warum du so starrhaft versuchst, ein Problem mit einem Werkzeug zu lösen, das dafür nicht ansatzweise geschaffen ist.



Das kann ich dir beantworten. Wenn ich einen Nagel in die Wand hauen muss um ein Bild aufzuhängen, aber nur eine Zange habe, dann verwende ich die eben als Hammer so gut es geht.

Allerdings ist das was hier abgeht eher damit zu vergleichen, das ich ein Bild aufhängen muss aber keinen Nagel besitze. Dafür aber ein Tesastrip (oder wie die auch immer heissen) und ich nun versuche diesen Tesastrip in die Wand zu schlagen um das Bild dran zu hängen 

Gruss

Claus


----------



## JuKu (26. Okt 2016)

JStein52 hat gesagt.:


> Was versteht ihr denn unter skalierbar ?



Ich meinte mit Skalierbarkeit in diesem Fall scaling out, also dass die Datenbank auf mehrere Server aufgeteilt wird (z.B. Google BitTable Technology). Das funktioniert bei MySQL aufgrund der Abhängigkeiten (z.B. INDEX, AUTO_INCREMENT usw.) nicht ganz so gut.


----------



## JStein52 (26. Okt 2016)

Die einen sagen so, die anderen so:
http://www.mysql.com/products/enterprise/scalability.html
ich kann es leider nicht beurteilen, ich bin kein Rechenzentrumsbetreiber.


----------



## JuKu (26. Okt 2016)

JStein52 hat gesagt.:


> Die einen sagen so, die anderen so:
> http://www.mysql.com/products/enterprise/scalability.html
> ich kann es leider nicht beurteilen, ich bin kein Rechenzentrumsbetreiber.



Diese Benchmarks sind aber nur für einen Server gedacht, also scaling up und nicht scaling out.
Wenn du dem Server mehr RAM und mehr CPU Cores gibst, kann er natürlich mehr Verbindungen handeln, aber irgendwann wird das extrem teuer, weshalb man lieber auf mehrere, verteilte Server, statt auf einen Super Server setzt.

Hier mal 2 Abbildungen, die den Unterschied sehr gut aufzeigen:











Vllt. weißt du jetzt, was ich mit scaling out meinte.


----------



## JStein52 (27. Okt 2016)

Erstens mal, wenn du solche Performance-Anforderungen hast dann hast du auch die fetten Server. Und zwar nicht nur einen.
Und zweitens meinte ich deshalb auch mehr diesen Absatz:

Many of the world's most trafficked web properties like Facebook, Twitter, Zappos and Zynga rely on MySQL performance and scalability to serve millions of users and handle their exponential growth. *MySQL Replication is the most popular and cost-effective way to deliver performance and scalability*. MySQL Thread Pool provides added scalability benefits in MySQL Enterprise Edition.

Edit: also Replication bringt das was du als scale out bezeichnet hast.


----------



## Tobse (27. Okt 2016)

JStein52 hat gesagt.:


> Erstens mal, wenn du solche Performance-Anforderungen hast dann hast du auch die fetten Server. Und zwar nicht nur einen.
> Und zweitens meinte ich deshalb auch mehr diesen Absatz:
> 
> Many of the world's most trafficked web properties like Facebook, Twitter, Zappos and Zynga rely on MySQL performance and scalability to serve millions of users and handle their exponential growth. *MySQL Replication is the most popular and cost-effective way to deliver performance and scalability*. MySQL Thread Pool provides added scalability benefits in MySQL Enterprise Edition.
> ...


+1 - MySQL Cluster funktionieren ziemlich gut.


----------



## JuKu (27. Okt 2016)

Tobse hat gesagt.:


> +1 - MySQL Cluster funktionieren ziemlich gut.



Dennoch sind Datenbanken wie Cassandra um einiges performanter:

http://www.datastax.com/wp-content/uploads/2012/08/WP-DataStax-MySQLtoCassandra.pdf
https://www.quora.com/Why-isnt-MySQ...olutions-or-hand-sharded-MySQL-configurations

Unabhängiger Benchmark:
https://academy.datastax.com/nosql-performance-benchmarks

Du brauchst für MySQL einfach viel mehr Nodes, um die selbe Leistung zu erzielen.


----------



## Meniskusschaden (27. Okt 2016)

JuKu hat gesagt.:


> Unabhängiger Benchmark:
> https://academy.datastax.com/nosql-performance-benchmarks


Ich kann dazu fachlich zwar nichts sagen, habe aber schon öfter gehört, dass jeder DB-Anbieter es schafft, Benchmarks zu erstellen, aus denen sein Produkt als Sieger hervor geht. Kann mir nicht vorstellen, dass ausgerechnet DataStax, die ihr Geld mit Cassandra verdienen, wirklich neutral ist.


----------



## JuKu (28. Okt 2016)

Meniskusschaden hat gesagt.:


> Ich kann dazu fachlich zwar nichts sagen, habe aber schon öfter gehört, dass jeder DB-Anbieter es schafft, Benchmarks zu erstellen, aus denen sein Produkt als Sieger hervor geht. Kann mir nicht vorstellen, dass ausgerechnet DataStax, die ihr Geld mit Cassandra verdienen, wirklich neutral ist.



Wenn du dir den Benchmark mal richtig angeschaut hättest, hättest du bemerkt, dass dieser von der Universität von Toronto stammt.
Datastax haben ihn lediglich auf ihre Seite kopiert.


----------



## JStein52 (28. Okt 2016)

JuKu hat gesagt.:


> dass dieser von der Universität von Toronto stammt.


Die Frage ist nicht wer ihn durchführt sondern wer ihn bestellt.


----------



## Meniskusschaden (28. Okt 2016)

JuKu hat gesagt.:


> Datastax haben ihn lediglich auf ihre Seite kopiert.


Man kopiert natürlich bevorzugt die Benchmarks auf die eigene Seite, deren Ergebnisse einem genehm sind.


----------



## Meniskusschaden (28. Okt 2016)

JuKu hat gesagt.:


> Wenn du dir den Benchmark mal richtig angeschaut hättest, ...


Ehrlich gesagt habe ich ihn mir überhaupt nicht angeschaut. Zum Einen habe ich unter dem Link gar keinen Benchmark gesehen (die Seite sieht bei mir ziemlich unvollständig aus), zum Anderen glaube ich ohnehin, dass Probleme nur selten durch den Wechsel der DB gelöst werden können, sondern eher durch durch das hier beschriebene Verfahren.


----------



## JuKu (28. Okt 2016)

Meniskusschaden hat gesagt.:


> Ehrlich gesagt habe ich ihn mir überhaupt nicht angeschaut. Zum Einen habe ich unter dem Link gar keinen Benchmark gesehen (die Seite sieht bei mir ziemlich unvollständig aus), zum Anderen glaube ich ohnehin, dass Probleme nur selten durch den Wechsel der DB gelöst werden können, sondern eher durch durch das hier beschriebene Verfahren.



Indexe machen WRITEs lahm, da sie sortiert werden müssen. Natürlich sind INDEXe das erste, was man machen kann, um READs zu optimieren. Aber FALLS man wirklich viele Daten (BigData) verarbeitet und damit auch schreibt, bringt so nen Index nichts.
Stell dir mal nen Spiel vor, dass auf MySQL setzt und ne Million WRITEs ausführt. Da würde ne MySQL Datenbank sicherlich schnell zusammen brechen.

Indexe sind Abhängigkeiten und müssen sortiert sein. Cassandra dagegen basiert auf Googles BigTable Technologie auf, da gibt es keine direkten Indexe mehr. Jeder Server sucht parallel und liefert das zurück, was er findet.

Aber wir sind vom Thema abgewichen, in diesem Thread ging es ja eig. um etwas komplett anderes.


----------



## neoexpert (29. Okt 2016)

,


----------



## mrBrown (29. Okt 2016)

Willst du ne ehrliche Meinung zu dem Design?


----------



## neoexpert (29. Okt 2016)

mrBrown hat gesagt.:


> Willst du ne ehrliche Meinung zu dem Design?


Ne ist ok. Ich bin noch am experimentieren. Bei der Suche werde ich in den Attributen suchen also
SELECT * FROM CATEGORIES WHERE TYPE = "ATTRIBUTE_VALUE"  AND VALUE LIKE "%SUCHWERT%"

TYPE wird auch im Index enthalten sein.
jeden Datensatz kriegt man dann in weniger als einer Millisekunde bei Z.B. 2^1000 Datensätzen. Daraufhin wird für jeden Datensatz geprüft, ob die Parent ID auf einen PRODUCT zeigt, was weitere (weniger als eine Millisekunde) Zeit benötigen wird (korrigiert mich wenn ich da falsch liege). Man könnte auch für bessere Performance eine spalte namens PARENT_TYPE einführen...

EDIT:
Ah, es kann ja sein dass "LIKE "%%"" zusätzliche Zeit benötigen wird.


----------



## JStein52 (29. Okt 2016)

neoexpert hat gesagt.:


> jeden Datensatz kriegt man dann in weniger als einer Millisekunde bei Z.B. 2^1000 Datensätzen.


Willst du uns verarschen ? Weiter oben hast du mal erklärt 2^1000 sei die Anzahl der Atome im Universum. D.h. du weisst zwar noch nicht wie du diese Datensätze abspeicherst aber du weisst dass du in weniger als einer Millisekunde jeden wiederfindest ?


----------



## JStein52 (29. Okt 2016)

neoexpert hat gesagt.:


> Ah, es kann ja sein dass "LIKE "%%"" zusätzliche Zeit benötigen wird.


Darauf kannst du einen lassen. besonders wenn er die Datensätze im Andromedanebel durchsucht.


----------



## Meniskusschaden (29. Okt 2016)

JStein52 hat gesagt.:


> Weiter oben hast du mal erklärt 2^1000 sei die Anzahl der Atome im Universum. D.h. du weisst zwar noch nicht wie du diese Datensätze abspeicherst aber du weisst dass du in weniger als einer Millisekunde jeden wiederfindest ?


Er nutzt eben auch die Atome der anderen Universen. Jetzt wird auch deutlich, was mit Skalierbarkeit gemeint war.


----------



## neoexpert (29. Okt 2016)

JStein52 hat gesagt.:


> Willst du uns verarschen ? Weiter oben hast du mal erklärt 2^1000 sei die Anzahl der Atome im Universum. D.h. du weisst zwar noch nicht wie du diese Datensätze abspeicherst aber du weisst dass du in weniger als einer Millisekunde jeden wiederfindest ?


Ja. Hypothetisch. Also wenn wir so einen Universum hätten (aber wer weiss es schon, keiner weiss was dunkle Energie ist)
und zwar ld(2^1000)=1000. Also bei einer binären Suche maximal 1000 vergleiche. Nehmen wir an wir vergleichen Integers. Moderne Rechner vergleichen 1000 Integers in weniger als einer Millisekunde.
Edit: übrigens: es soll weniger als 2^1000 Atome geben. Ich habe 2^1000 nur als Beispiel genannt.


----------



## neoexpert (29. Okt 2016)

Wurde ja oft gefragt: mit der Skalierung meine ich halt, dass man die Tabelle sozusagen dynamisch im der Breite anpassen kann. Deshalb Skalierung, weil man die Tabelle sozusagen ausdehnt (durch hinzufügen von Spalten) oder komprimiert (durch löschen von Spalten)


----------



## JStein52 (29. Okt 2016)

Ach so. ein ALTER TABLE also.


----------



## JuKu (29. Okt 2016)

Aber wozu?
Welchen Sinn hat das denn bitte, wenn du immer dynamische Spalten hast?
Dann kannst du die Performance wieder nicht optimieren.


----------

