Worum es geht
Viele Frameworks laden erst ein ganzes Objekt und schneiden danach weg, was der Client nicht will. CDMS macht es umgekehrt: Die response wird vor der Datenbankabfrage ausgewertet, und die Abfrage liest nur die Spalten, die du angefordert hast.
Drei Begriffe, die auf dieser Seite vorkommen:
| Begriff | Bedeutung |
|---|---|
| Projektion | Die Abfrage liest nur ausgewählte Spalten statt der ganzen Zeile. In CDMS heißt die Technik „Tuple-Projektion“: Das Ergebnis ist eine Liste von Werten statt eines vollständigen Objekts. |
| LEFT JOIN | Verbindet eine Tabelle mit einer zweiten, ohne Zeilen zu verlieren, bei denen es keine Verbindung gibt. Ein Mitarbeiter ohne Firma bleibt also im Ergebnis, sein Firmenfeld ist leer. |
| Nachladen (Lazy Loading) | Ein Framework lädt eine Referenz heimlich nach, sobald der Code darauf zugreift. Das gibt es beim Lesen in CDMS nicht. |
Von der response zur SQL-Abfrage
Links steht die response, rechts, was CDMS daraus macht (vereinfacht):
flowchart LR
subgraph R["response"]
direction TB
r1["firstname"]
r2["lastname"]
r3["{ field: company, response: [companyname] }"]
end
subgraph S["SQL für employee"]
direction TB
s1["SELECT e.id, e._createdOn, e._updatedOn, Typ,<br/>e.firstname, e.lastname,<br/>c.id, Typ von c"]
s2["FROM employee e<br/>LEFT JOIN company c ON e.company_id = c.id"]
s3["WHERE e.id = '7f3…' UND Zeilenfilter"]
s1 --> s2 --> s3
end
subgraph T["SQL für company"]
direction TB
t1["SELECT c.id, c._createdOn, c._updatedOn, Typ,<br/>c.companyname"]
t2["FROM company c<br/>WHERE c.id = 'a1…' UND Zeilenfilter"]
t1 --> t2
end
R ==> S
S ==>|"company.id"| T
Drei Dinge siehst du daran:
- Nur verlangte Spalten. Aus
employeeliest CDMSfirstnameundlastname, dazu immerid,_createdOn,_updatedOnund den Typ. Andere Spalten fasst die Abfrage nicht an. - Die Referenz kommt per LEFT JOIN, aber nur mit
idund Typ. So weiß CDMS, auf welches Objektcompanyzeigt, ohne dessen Spalten zu lesen. - Die ausgebaute Referenz ist ein eigenes Lesen. Mit der
idliest CDMS diecompanyüber ihr eigenes Modell. Dabei gelten ihre Rechte, ihre Zeilenfilter und ihre Lese-Hooks, genau wie bei einem direktenread.
Die drei Schritte einer Abfrage
Jede Abfrage, auch das Lesen eines einzelnen Objekts, läuft in drei Schritten:
-
1CDMS→Datenbankzählen: Wie viele Zeilen passen zum Filter?Das ergibt
totalCountinmeta. Sind es null Zeilen, ist CDMS hier schon fertig. -
2CDMS→DatenbankIDs bestimmen: Welche Zeilen kommen auf diese Seite? Mit Filter, Sortierung,
limitundpage, aber nur mit den IDs -
3CDMS→DatenbankFelder holen: Für genau diese IDs die angeforderten Spalten lesen, Referenzen per LEFT JOIN
-
4CDMSsetzt die Werte zu Objekten zusammen, in der Reihenfolge aus Schritt 2
Die Werte kommen als flache Liste mit Namen wie company.id zurück. CDMS macht daraus wieder eine verschachtelte Struktur: { "company": { "id": … } }.
Wann es teuer wird
Eine einzelne Abfrage ist dank Projektion schnell. Teuer wird es durch die Anzahl der Abfragen. Jede ausgebaute Referenz und jede ausgebaute Liste ist eine eigene Abfrage, und zwar pro Objekt, das sie enthält.
Wann: POST /hr/employee/query mit limit: 25 und response: ["firstname", "lastname"]
Eine Abfrage auf employee, ohne JOIN.
Ergebnis: 1 Abfrage (in drei Schritten).
Wann: … und zusätzlich { "field": "company", "response": ["companyname"] }
Die employee-Abfrage bekommt einen LEFT JOIN für die id der Firma. Danach liest CDMS für jeden der 25 Mitarbeiter seine Firma.
Ergebnis: bis zu 1 + 25 Abfragen. Mitarbeiter ohne Firma brauchen kein zweites Lesen.
Wann: response: ["*"] auf employee mit den Referenzen company und department
* fordert jede Referenz mit ihrer id an. Auch das ist für jede Referenz ein eigenes Lesen, damit Rechte und Zeilenfilter des Zielmodells gelten.
Ergebnis: bis zu 1 + 25 × 2 Abfragen.
Wann: POST /hr/company/query mit limit: 25 und { "field": "employees", "response": ["firstname"] }
Für jede der 25 Firmen eine eigene Suche auf employee. Ohne limit in der Liste liefert jede Suche alle Mitarbeiter ihrer Firma.
Ergebnis: 1 + 25 Abfragen, bei 500 Mitarbeitern je Firma 12 500 Objekte.
Wann: … und in employees zusätzlich { "field": "department", "response": ["name"] }
Für jeden gelesenen Mitarbeiter kommt eine Abfrage für seine Abteilung dazu. Die Zahl multipliziert sich von Ebene zu Ebene.
Ergebnis: 1 + 25 + 25 × (Mitarbeiter je Firma) Abfragen.
Untertypen abstrakter Modelle
Liegt ein Feld nicht im Obermodell, sondern in einem Untertyp, verbindet CDMS die Tabelle des Untertyps über die gemeinsame id. Bei einer abstrakten Liste sucht CDMS erst auf dem Obermodell nur die IDs und Typen und liest dann je Untertyp alle seine Treffer mit einer Abfrage (id IN (…)). Siehe Lesen über abstrakte Typen.
Entscheidungstabelle
| Eintrag | Wirkung auf die Datenbank |
|---|---|
| einfaches Feld, z. B. "firstname" | eine Spalte mehr in derselben Abfrage |
| "+" | alle einfachen Spalten in derselben Abfrage |
| Einzelreferenz über * oder { field } | ein LEFT JOIN, dazu ein Lesen pro Objekt |
| Liste über * oder { field } | eine Suche pro Objekt, ohne limit mit allen Einträgen |
| Objekt in einem Objekt | multipliziert sich mit der Ebene darüber |
Faustregeln
{ "response": ["firstname", "lastname"], "parameter": { "limit": 25 } }- eine Abfrage, egal wie viele Referenzen das Modell hat
{ "response": ["+", { "field": "company", "response": ["companyname"] }] }- zusätzliche Abfragen nur für das eine geöffnete Objekt
Wie es weitergeht
- Feldauswahl im Detail: Feldauswahl mit
response - Listen in Objekten: Referenzen und Listen ausbauen
- Filter in verschachtelten Listen: Filter in verschachtelten Listen