Ist JSON als column jetzt der neue Standard oder hab ich was verpasst?

Thallius

Top Contributor
Auf Stackoverflow sieht man jetzt täglich mehrere Fragen wie diese


Wobei die noch harmlos ist. teilweise werden ganze objecte als JSON in einer column gespeichert und dann wird gefragt wie man nach einem object suchen kann das bestimmte Attribute hat.

ich würde niemals auf die Idee kommen sowas zu bauen, das muss doch Grotten langsam sein wenn man dann nach Attributen des objects sucht. Ist das heutzutage auch total egal und man argumentiert „Kauf doch schnellere Hardware“ Nur um sich bei der Erstellung der Datenbank keine Gedanken machen zu müssen und halt sehr einfach die Objekte ändern kann ohne die Datenbank anpassen zu müssen?
da kann ich dann aber doch auch gleich alles in eine Text Datei schreiben und selber drin suchen, das wäre ja noch Performanter...

Ist es also wirklich so, dass man heutzutage überhaupt nicht mehr drüber nachdenkt wie man seine Daten sinnvoll speichert weil es ja quasi eine menschliche Optimierung ist und optimieren tut heute ja der Computer...
 

httpdigest

Top Contributor
Also in relationalen Datenbanken hab ich das auch noch nicht gesehen, allerdings ein paar Projekte mit dokumentenbasierten Datenbanksystemen wie MongoDB.
Da ist es dann aufgrund der Natur der Datenbank wiederum sehr angenehm, ganze Objektbäume schemalos als "Entitäten" zu speichern und queries darauf abzusetzen. Selbstverständlich können dort Propertypfade dann auch indexiert werden und (wie etwa bei Oracle) schlägt einem MongoDB auch vor, welche Attributpfade häufig angefragt werden und sinnvoll indexiert werden könnten.
Solche "schemalosen" Datenbanken haben durchaus ihren Charme. Allerdings übersieht man hier leicht, dass das "Schema" mit den Constraints ja nichts ist, was inhärent der relationalen Datenbank innewohnt, sondern fachlich getrieben ist und man bei schemalosen Datenbanken ganz andere Probleme bekommt, die Daten konsistent zu halten. Hier verlagert sich das Forcieren eines Schemas dann eben in die Anwendungslogik/-schicht, wenn es bei RDBMS'ses eben als Teil der Schemamodellierung direkt in der Datenbank angesiedelt sein kann.
 
K

kneitzel

Gast
Als kleine Ergänzung zu httpdigest vielleicht noch ein kleiner Hinweis:

Bei dem SQL Server von Microsoft gibt es die Möglichkeit, bei einem column auch ein Schema festzulegen und so. Intern wird das dann nicht mehr als XML gespeichert sondern es gibt eine Art virtuelle Tabellen und die Zugriffe sind ähnlich optimiert möglich. Das hat in der Praxis aber einige Probleme mit sich gebracht - eine Schema-Änderung konnte dann schon mal recht viel Zeit in Anspruch nehmen und die Dokumentation diesbezüglich ist auch schwer zu finden (fand ich).

Sowas ist prinzipiell auch bei JSON denkbar mittels JSON Schema - auch wenn das irgendwie nicht wirklich verbreitet ist...
 

Thallius

Top Contributor
Hätte ich vielleicht dabei schreiben sollen, dass es mir dabei nur um relational DB geht. Die Fragen kommen immer für irgendwelche SQL derivate
 
K

kneitzel

Gast
Ja, so hatte ich Dich auch verstanden. Aus meiner Sicht ein Unding. Zumal ich da keinen Vorteil sehe. Dann doch lieber "flatten" - dann hat man Daten halt in einer Tabelle mit parentId, key, value und ggf datatype

So XML oder JSON Strukturen lassen sich schön "flatten" so dass man nur noch eine Map hat a.la.
node1.node2[2].@attrib
was dann etwas wäre wie:
XML:
<node1>
    <node2 />
    <node2 />
    <node2 attrib="some value"/>
</node1>
Nur um es mal als XML anzudeuten und dabei alles mögliche weg zu lassen ...

Das Suchen geht immer noch nicht zu gut - aber man kann indizieren und so ... Und es muss keine Stuktur geparst werden. Das ist bei XML tödlich, wenn man bei jedem Schreibzugriff dann XML als String liest, in eine Struktur parst um es dann zurück zu schreiben ...

Und wenn ich hier XML erwähne: Klar: JSON ist nicht XML, aber ich sehe das ähnlich und die Aussagen gelten 1:1. Meine Erfahrungen gehen aber halt auf XML zurück.
 

mrBrown

Super-Moderator
Mitarbeiter
"Neu" meint dabei aber fast 20 Jahre, so lange gibt schon XML-Columns ;)

Ganz generell können die auch durchaus sinnvoll sein, zB für typische EAV-Modelle oder auch sowas wie Tags die zu Entitäten hinzugefügt werden können. Da können die auch aus Performance-Sicht besser sein.

Das Suchen geht immer noch nicht zu gut - aber man kann indizieren und so ...
Es lassen sich durchaus auch Indizes auf JSON-Columns erstellen.

Und es muss keine Stuktur geparst werden. Das ist bei XML tödlich, wenn man bei jedem Schreibzugriff dann XML als String liest, in eine Struktur parst um es dann zurück zu schreiben ...
Speichert irgendeine Datenbank json und xml noch als "plain text"?
 
K

kneitzel

Gast
Speichert irgendeine Datenbank json und xml noch als "plain text"?
Das kann ich nicht sagen, da ich da die Internas der ganzen Datenbanken schlicht nicht gut genug kenne.

Für meinen Punkt war es aber nicht relevant, denn da ging es um das lesen / schreiben des ganzen Feldes. Und wenn das Feld abgefragt wird, dann kommt natürlich ein JSON oder XML zurück. Und wenn das zurück geschrieben wird, dann muss es verarbeitet werden.

Also entweder die Datenbank kann XML/JSON irgendwie anders intern verwalten. Dann ist nach einem Schreiben eines Feldes der Inhalt entsprechend auszuwerten und in die Strukturen zu schreiben. Und beim Auslesen dann der Weg zurück -> Mehr Aufwand
Der Vorteil, dass man auf Teile schnell zugreifen kann, wird also mit entsprechendem Aufwand "gekauft". Und evtl. gibt es schnelle und einfache Operationen, um Teile zu verändern - die müssen dann aber auch entsprechend genutzt werden.

Ich sehe das relativ kritisch wobei ich auf die Erfahrung mit einem Projekt beziehe. Da mag evtl. das eine oder andere schief gegangen sein. Aber da hatten wir tatsächlich "XML Datastores" in der Datenbank. Wir haben da sogar XSDs erzwungen um die Laufzeit vernünftig hin zu kriegen. Updates auf dem Datastore waren aber dennoch die Hölle und schwer zu optimieren. Unsere Lösung war, dass dann einzel-Änderungen nicht mehr an die Datenbank gegeben wurden sondern Änderungen gesammelt und dann in einer Transaktion in den Datastore geschrieben wurden, (Bei größerem Datastore war eine Anpassung teilweise 1s ... bei 10.000 Updates kann man sich dann ausrechnen, was das für Laufzeiten bedeutet ... Also wurden die 10.000 Datensätze angepasst und dann ein einziges Update geschrieben.

Es mag sein, dass es noch besser optimiert hätte werden können. Das kann ich nicht ausschließen. Aber der Code dahinter war schon so das, was ich als schwer verständlich ansehen würde. zumal wir uns da auch massiv um Internas vom SQL Server kümmern mussten, die eben nicht so offen bekannt waren oder dessen Dokumentation man erst einmal finden / bekommen musste.... Ich würde es zukünftig nicht mehr so bauen - das muss ich ganz klar sagen. Aus der Erfahrung heraus wäre eine traditionelle, relationale Speicherung deutlich besser (Sowohl aus Sicht der "Verständlichkeit" als auch aus sicht der Performance .... Wobei das vielleicht heutzutage besser geworden ist ... Microsoft hat in dem Bereich einiges mehr gemacht und verbessert - das war damals SQL Server 2012 oder so ... Oder erst 2008 und dann 2012? Ich erinnere mich nicht mehr im Detail ...)
 

mrBrown

Super-Moderator
Mitarbeiter
Ist es also wirklich so, dass man heutzutage überhaupt nicht mehr drüber nachdenkt wie man seine Daten sinnvoll speichert [...]
Dieser Thread ist übrigens (mal wieder) ein wunderbares Beispiel, dass wirklich zu viele Leute (gut, hier nur eine Person wirklich nicht drüber nachdenken, wie man Daten sinnvoll speichert. :)


Wahrscheinlich ist der Thread aber auch wieder ein Beispiel dafür, dass man vom TO nichts Substanzielles mehr hört :(
 

mrBrown

Super-Moderator
Mitarbeiter
Das ist sehr interessant - dann hat sich da doch einiges getan in den letzten Jahren ...
Ich würde erwarten, dass sich in den letzten 5 Jahren durchaus auch noch was geändert hat, der Artikel ist ja schon ein paar Versionen alt – in welche Richtung das allerdings ausschlägt mag ich nicht beurteilen.
Vielleicht hat ja grad jemand Zeit und Lust, das mal mit der aktuellsten Postgres-Version zu testen? :)
 

Thallius

Top Contributor
Dieser Thread ist übrigens (mal wieder) ein wunderbares Beispiel, dass wirklich zu viele Leute (gut, hier nur eine Person wirklich nicht drüber nachdenken, wie man Daten sinnvoll speichert. :)


Wahrscheinlich ist der Thread aber auch wieder ein Beispiel dafür, dass man vom TO nichts Substanzielles mehr hört :(

oha jetzt musst du sogar schon persönlich werden.

Naja mir ist es egal. Es kann nicht alles falsch sein was ich mache wenn mich meine Auftraggeber schon seit Jahrzehnten immer wieder beauftragen neue Software für sie zu entwickeln, so dass ich mittlerweile vieles ablehnen muss weil ich nicht mehr als 60h die woche arbeiten will. Da kannst du wettern wie du willst denn du bist in meine Augen halt nicht wichtig für mich und ich werde weiterhin meinen Spaß daran haben dich auf die Palme zu bringen mit meinen altmodischen Ansichten....
 

mrBrown

Super-Moderator
Mitarbeiter
Wie vermutet: nachdem man erst völligen Unsinn redet und dann korrigiert wird, kommt nichts mehr zum Thema sondern nur noch Ablenken mit "ich bin ja so gut".

Es wäre so schön, wenn wenigstens einmal ein paar fundierte Argumente kommen würden...
 

Thallius

Top Contributor
Was soll ich zu dem Thema schreiben? Der Artikel untermauert genau was ich gesagt habe man muss ihn nur anders auslegen. Selbst dieses für JSON optimierte Beispiel langt nur um die doppelt so langsam zu sein wie eine ordentlich aufgebaute Datenbank.
 

mrBrown

Super-Moderator
Mitarbeiter
Was soll ich zu dem Thema schreiben? Der Artikel untermauert genau was ich gesagt habe man muss ihn nur anders auslegen. Selbst dieses für JSON optimierte Beispiel langt nur um die doppelt so langsam zu sein eine ordentlich aufgebaute Datenbank.
Du hast vermutlich in der letzten Grafik den Balken zu der JSONB-Variante mit Index übersehen. Der ist halt auch wirklich schlecht sichtbar ;)
5AAC01C8-8AB3-4FD3-AFBF-85C63DEDA105.jpeg
 

mrBrown

Super-Moderator
Mitarbeiter
Abgesehen davon:
Selbst dieses für JSON optimierte Beispiel
Was ist denn das für eine bescheuerte Haltung?

Um die Vorteile von etwas zu zeigen, nimmt man natürlich immer den (realistische!) Anwendungsfall, in dem man es aufgrund der Vorteile benutzen würde. Man bewertet ja LKWs auch nicht daran, wie gut sie sich gegen Formal 1-Wagen auf dem Nürburgring machen – und genausowenig Formel 1-Wagen daran, wie gut sie Paletten transportieren.

Soll man sich lieber einen Anwendungsfall ausdenken, in dem JSON völlig ungeeignet ist und bei dem deshalb niemand JSON nutzen würde, nur damit dann solche wie Du darüber meckern können, wie ungeeignet JSON ja alles ist?
 

Thallius

Top Contributor
Der anwendungsfall ist doch komplett weltfremd. Wie oft hast du denn Bitteschön eine entity die nur aus strings besteht?

nehmen wir doch mal was reelles.

class order
{
int number;
Customer customer;
ArrayList<articles> articleList;
LocalDate date;
}

class Customer
{
int Number;
String name;
ArrayList<Address> address;
}

class Article
{
Int number;
String name;
Int price;
}

jetzt hau so eine Order entity mal in ein JSON column und suche dann nach dem Gesamtumsatz aller Kunde aus Köln des letzten Jahres....
 

mrBrown

Super-Moderator
Mitarbeiter
Dein Beispiel ist ein völlig anderer Anwendungsfall.
Füg in einem Modell mal dem Article beliebige Properties zur Laufzeit hinzu. Das ist der Anwendungsfall, um den es in dem Beispiel geht. Ganz klassisches EAV-Modell.
 
K

kneitzel

Gast
Der anwendungsfall ist doch komplett weltfremd. Wie oft hast du denn Bitteschön eine entity die nur aus strings besteht?
Darum geht es nicht einmal. Du kannst das ja noch beliebig erweitern. Im JSON kann durchaus ein typ stecken und dann hast Du halt auf Code-Seite eine etwas größere Auswertung. Wichtig ist halt nur die (De)Serialisierung vom JSON und der entsprechende Umgang. Aber ob da nun ein Wert nur "Bla Bla" ist oder ein
JSON:
{
    type: String
    value: "BlaBla"
}
und dann statt String da alles mögliche sein kann (int, long, UUID, ByteArray, ....

Also ich sehe da erst einmal kein Problem. In einer Datenbank wirst Du da ggf. auch vereinfachen und z.B. einen String kodierten Wert abspeichern. Ansonsten wird das schnell relativ komplex fürchte ich ...
 

mrBrown

Super-Moderator
Mitarbeiter
Und das sagt dann der, der sagt man soll immer den passenden Datentypen benutzen. Int, float und Boolean in einem Json sind natürlich perfekt passend....
Ähm; boolean, number und string sind die einzigen primitiven Typen in JSON, da gibts keine anderen. Die zu nutzen ist also genau passend, anders als einfach String für alles zu nutzen. Die Datenbank unterscheidet da auch zwischen boolean, number und string.
 

mihe7

Top Contributor
@Thallius, ich habe mich bislang mangels Anforderung auch nicht damit beschäftigt und bin nicht gerade derjenige, der auf jeden Hype aufspringt oder der Meinung ist, mein sorgloser Umgang mit Ressourcen kann der Kunde ruhig mit mehr RAM ausgleichen, aber die Ergebnisse finde ich sehr überzeugend. Allerdings braucht man halt auch einen entsprechenden Anwendungsfall, da fällt mir ad hoc nichts ein, wo das in unserer Software einen nennenswerten Vorteil bringen würde. Wenn man dem Kunden aber z. B. von ihm definierte Felder anbieten möchte, dann bietet sich der Spaß doch geradezu an.
 

mrBrown

Super-Moderator
Mitarbeiter
nehmen wir doch mal was reelles.

[...]

jetzt hau so eine Order entity mal in ein JSON column und suche dann nach dem Gesamtumsatz aller Kunde aus Köln des letzten Jahres....

Habs getestet.

Modell sieht so aus (falls irgendwem was auffällt, gerne korrigieren!):

SQL:
CREATE TABLE Order
(
    ID       int PRIMARY KEY,
    customer jsonb,
    articles jsonb
);
CREATE INDEX ON Order USING GIN (customer jsonb_path_ops);
SQL:
CREATE TABLE Customer
(
    ID   int PRIMARY KEY,
    name varchar(255)
);

CREATE TABLE Address
(
    Customer_ID int REFERENCES Customer (ID),
    street      varchar(255),
    city        varchar(255)
);
CREATE INDEX ON Address (city);
CREATE INDEX ON Address (Customer_ID);

CREATE TABLE "Order"
(
    ID          int PRIMARY KEY,
    Customer_ID int REFERENCES Customer (ID)
);
CREATE INDEX ON "Order" (Customer_ID);
CREATE TABLE Article
(
    ID    int PRIMARY KEY,
    name  varchar(255),
    price int
);
CREATE TABLE Order_Article
(
    Article_ID int REFERENCES Article (ID),
    Order_ID   int REFERENCES "Order" (ID)
);
CREATE INDEX ON Order_Article (Order_ID, Article_ID);


Selects sehen so aus ("City4" weil einfach "City1" bis "CityN" existieren, sollte ja ein passender Ersatz für Köln sein):

SQL:
SELECT SUM(a.PRICE), Customer_ID
FROM (SELECT Order.customer -> 'id' as Customer_ID,
             (jsonb_array_elements(Order.articles) -> 'price')::numeric price
      FROM Order
      WHERE Order.customer @> '{"addresses":[{"city":"City4"}]}') a
GROUP BY Customer_ID
SQL:
SELECT SUM(Article.PRICE), C.ID
FROM (SELECT DISTINCT Customer.ID
      FROM Customer
               JOIN Address on Customer.ID = Address.Customer_ID
      WHERE Address.city = 'City4') AS C
         JOIN "Order" O on C.ID = O.Customer_ID
         JOIN Order_Article on O.ID = Order_Article.Order_ID
         JOIN Article on Order_Article.Article_ID = Article.ID
GROUP BY C.ID


Ein Vergleich ist schwierig, weil das so viele Dimensionen hat, deshalb einfach nur ein paar Exemplarische Werte.
Größere Werte hab ich aus Zeitgründen grad nicht getestet, falls aber jemand Lust hat, das mal ein paar Stunden laufen zu lassen...

mit JOIN JSONBmit JSONB JOIN
customers 10000
with_second_address 1000
addresses 20
articles 200
articles_per_order 10
orders_per_customer 20
113.776 ms67.202 ms
customers 100000
with_second_address 1000
addresses 20
articles 200
articles_per_order 10
orders_per_customer 20
951.150 ms354.847 ms
customers 10000
with_second_address 1000
addresses 2000
articles 2000
articles_per_order 10
orders_per_customer 20
3.442 ms3.366 ms
customers 10000
with_second_address 1000
addresses 2000
articles 2000
articles_per_order 200
orders_per_customer 10
12.104 ms6.861 ms
customers 10000
with_second_address 1000
addresses 2000
articles 2000
articles_per_order 10
orders_per_customer 200
14.147 ms8.905 ms
 
Zuletzt bearbeitet:

Thallius

Top Contributor
Du würdest ohne json ja auch nicht FROM customer machen sondern FROM Address wenn du eh nur alle haben willst die city4 sind. So ist klar das du einen Riesen overhead mit rumschleppst wenn du alle customer checkst und die cities joins.
 

mrBrown

Super-Moderator
Mitarbeiter
Du würdest ohne json ja auch nicht FROM customer machen sondern FROM Address wenn du eh nur alle haben willst die city4 sind. So ist klar das du einen Riesen overhead mit rumschleppst wenn du alle customer checkst und die cities joins.

So?
SQL:
SELECT SUM(Article.PRICE), C.ID
FROM (SELECT DISTINCT Customer_ID AS ID FROM Address WHERE Address.city = 'City4') AS C
         JOIN "Order" O on C.ID = O.Customer_ID
         JOIN Order_Article on O.ID = Order_Article.Order_ID
         JOIN Article on Order_Article.Article_ID = Article.ID
GROUP BY C.ID

Habs grad nur für das erste getestet; sind dann "nur noch" 64.309 ms statt 67.202 ms.


EDIT: alle Zeitangaben im englischer Schreibweise...
 

Thallius

Top Contributor
Probier es mal so

Java:
SELECT SUM(Article.PRICE), C.ID
FROM Address A
LEFT JOIN Customer C ON C.ID = A.Customer_ID
LEFT JOIN "Order" O on C.ID = O.Customer_ID
LEFT JOIN Order_Article on O.ID = Order_Article.Order_ID
LEFT JOIN Article on Order_Article.Article_ID = Article.ID
WHERE A.city = 'city4'
GROUP BY C.ID
 

Thallius

Top Contributor
Ok, dass liegt halt daran das mein Datenmodell nur so hingelascht ist. Normalerweise muss man ja eine Beziehung von Order zu Adresse haben sonst weiß man ja gar nicht wo die order hingeliefert wurde
 
K

kneitzel

Gast
Wobei die genauen Werte erst einmal nebensächlich sind. Es ist schön gezeigt, dass es mit JSON durchaus performant sein kann ...

Und das war ja auch die eigentliche Fragestellung, oder übersehe ich da jetzt was?
 

Thallius

Top Contributor
Wobei die genauen Werte erst einmal nebensächlich sind. Es ist schön gezeigt, dass es mit JSON durchaus performant sein kann ...

Und das war ja auch die eigentliche Fragestellung, oder übersehe ich da jetzt was?

Das Problem ist, was passiert wenn der Customer sich nun umfirmiert und einen anderen Namen bekommt? Mal ganz abgesehen davon, das die Tabelle tausendfach größer sein dürfte weil jede order den kompletten customer beinhaltet.

Ich habe ja im Eröffnungspost nicht generell die Brauchbarkeit einer JSON column bezweifelt. Sicher gibt es hier Anwendungsmöglichkeiten. Wäre ja sonst auch nicht implementiert worden. Aber so wie das im Moment anscheinend inflationär genutzt wird, kann ich mir nicht vorstellen das die Leute überhaupt wissen was sie da tun und einfach nur mal wieder den leichteren Weg nehmen beim programmieren, was dann letztendlich bei langsamer und user unfreundlichen Software führt.
 

mrBrown

Super-Moderator
Mitarbeiter
Ok, dass liegt halt daran das mein Datenmodell nur so hingelascht ist. Normalerweise muss man ja eine Beziehung von Order zu Adresse haben sonst weiß man ja gar nicht wo die order hingeliefert wurde
Hab einfach mal Address.Customer_ID zu Address.Order_ID geändert (und das json-Modell auch entsprechend angepasst).

Die JSON-Variante sinkt dann auf 51.027ms, weil dann ein vernünftiger Index möglich ist. Die Variante mit Joins bleibt etwa gleich (± ein paar ms) – da ist dann die Variante mit JSON schneller :)
 

Ähnliche Java Themen

Neue Themen


Oben