maandag 8 februari 2016

Object hiërarchie in een database

De aansluiting van een relational database management system (RDBMS) op een logisch objectenmodel is altijd nog een uitdaging (of veel werk), simpelweg omdat het conceptueel niet op elkaar aansluit. PostgreSQL is onderwater echter object-gericht (ORDBMS) en kan zo aan deze tekortkoming enigszins tegemoet komen.

Voor het beschrijven van kenmerken van (geo) objecten wordt gebruik gemaakt van de Aquo standaard. De onderstaande plaat (afkomstig uit de Aquo praktijkrichtlijn IMWA, 2009) en geeft een hiërarchie in objectklassen aan:




Het gaat daarbij niet zozeer om de inhoud van de plaat, maar het concept van hiërarchie. Hoe kun je dat slim (her)gebruiken voor gegevensbeheer? Een traditioneel ingerichte database normaliseert bovenstaand model naar meerdere tabellen met de nodige hulptabellen en foreign-keys relaties. Dat wordt al snel een complex en uitgebreid databasemodel, met alle gevolgen voor database- en gegevensbeheer.
Voor het bevragen van data moeten complexe SQL queries opgesteld worden en applicaties kunnen niet altijd even makkelijk op het datamodel van de database aansluiten.
Kan dat niet beter?

DEMO

Postgres, als oject-gericht database systeem, kent de mogelijkheid van tabelovererving dat voor DEMO prima toegepast kan worden.
Daarom is om te beginnen op het hoogste objectniveau een tabel met de naam object gemaakt:

CREATE TABLE object
(
   object_pk serial PRIMARY KEY,
   naamruimte varchar,
   guid UUID DEFAULT (SELECT uuid_generate_v4()),
   objectbegintijd timestamp DEFAULT CURRENT_TIMESTAMP,
   objecteindtijd timestamp,
   tijdstipregistratie timestamp DEFAULT CURRENT_TIMESTAMP,
   eindregistratie timestamp,
   inonderzoek boolean
)
WITH (
   OIDS=FALSE
);
ALTER TABLE object OWNER TO postgres;




Deze tabel bevat de essentiële metadata over een object, maar geen enkele eigenschap van een object (uitgezonderd de guid), zelfs het objecttype ontbreekt.
Eén niveau dieper komen we bij fysieke - en registratieve objecten. Deze tabellen bevatten door overerving in ieder geval de bovenstaande metadata van object en voegen daar nieuwe attributen op het juiste aggregatieniveau aan toe. Bijvoorbeeld:


CREATE TABLE fysiekobject
(
   status public.objectstatus,
   ontstaanswijze public.ontstaanswijze,
   CONSTRAINT fysiekobject_pk PRIMARY KEY(object_pk)
) INHERITS (object)
WITH (
   OIDS=FALSE
);
ALTER TABLE public.fysiekobject OWNER TO postgres;




Er zijn nog meer kenmerken denkbaar, maar het moet wel passen bij dit aggregatieniveau. Kenmerken als wie is de eigenaar, wie pleegt het onderhoud zijn hier misplaatst, daar is een fysiek object te generiek voor. Zelfs met algemene kenmerken als Wat heeft dit fysieke object gekost (stichtingskosten) loop je al snel tegen beperkingen aan (in de zin van 'niet nuttig' of zelfs 'niet bruikbaar').
De hiërarchie daalt vervolgens een stap dieper af naar bijvoorbeeld oppervlaktewaterlichaam.


CREATE TABLE oppervlaktewaterlichaam
(
   code varchar,
   naam varchar,
   watertypekwalitatief public.watertypekwalitatief,
   watertypekwantitatief public.watertypekwantitatief,
   categorieoppwaterlichaam public.categorieoppwaterlichaam,
   persistentie public.persistentie,
   breedte numeric(9,3),
   lengte numeric(9,3),
   oppervlakte numeric(10),
   niveau varchar DEFAULT 'maaiveld',
   geometrie public.vlakoflijn,
   actor varchar,
CONSTRAINT oppervlaktewater_pk PRIMARY KEY(object_pk)
) INHERITS (fysiekobject)
WITH (
  OIDS=FALSE
);
ALTER TABLE oppervlaktewaterlichaam OWNER TO postgres;
GRANT SELECT ON oppervlaktewaterlichaam TO PUBLIC;




Deze tabel omvat door de overerving ook de kolommen van fysiekobject en indirect van object.
Iedere tabel in de lijn is verantwoordelijk voor de eigen toegangsregels, indexen, triggers, procedures e.d. Daarbij zijn constraints en sequences wel gezamenlijk te gebruiken. Zie ter illustratie het gebruik van individuele PRIMARY KEY CONSTRAINTs in bovenstaande tabellen op basis van één object_pk.


Met oppervlaktewaterlichaam komen we op het niveau van de databeheerder. Vanaf dit niveau moeten de GRANTs toegekend en de Row Level Security (RLS) ingericht worden, niet eerder. Toegang tot bovenliggende tabellen wordt automatisch gepropageerd, andersom niet.


Met deze objectgerichte opzet worden twee zaken bereikt:
  • Database bevat relatief weinig tabellen en relaties.
  • Tabeldefinities zijn compact en leesbaar.
  • Het datamodel is consistent. Er is geen objecttype te definiëren waarbij essentiële attributen worden vergeten. Bijvoorbeeld: ieder object dat afgeleid is van fysiek object heeft per definitie een status.
  • Op ieder aggregatieniveau zijn de gegevens met simpele one-liners op te vragen:
    • Hoeveel objecten zijn er, gegroepeerd naar objecttype?
    • Hoeveel kunstwerken zijn er, gegroepeerd naar kunstwerktype?
    • Visualiseer ALLE storingen op enig moment.
    • Hoeveel en welke objecten bevatten naar alle waarschijnlijkheid foutieve gegevens en zijn in onderzoek?


Mooi toch ?


Geen opmerkingen:

Een reactie posten