donderdag 7 augustus 2008

Vloeibare relaties

SQL is ongetwijfeld één van de baanbrekende standaarden van de software-industrie. De officiële standaard dateert uit 1986; inmiddels is SQL:2006 alweer de zesde versie. En SQL is springlevend. Het is zonder meer knap om in een industrie die zo in beweging is een standaard te ontwikkelen die al zo lang zo algemeen wordt gebruikt. Toch heb ik de indruk dat er een tot op heden onbenut verbeterpotentieel verborgen zit in deze populaire standaard. Het is de hoogste tijd voor een

Zoektocht door de tijd

SQL is sterk verbonden met het relationele model van wijlen Edgar Codd. Deze legendarische Britse wetenschapper publiceerde in 1969 al een artikel onder de titel "A Relational Model of Data for Large Shared Data Banks" [1] waarin de theoretische basis werd gelegd voor de relationele databases van vandaag de dag.

SQL is primair nog steeds een querytaal. Er zullen maar weinig IT-ers fronsen bij de aanblik van een statement als

SELECT *
FROM Medewerker
WHERE Salaris > 10.000
ORDER BY Geboortedatum;

Het relationele model is gebaseerd op tabellen, zoals de tabel “Medewerker” in het bovenstaande voorbeeld, en de relaties tussen tabellen, bijvoorbeeld tussen “Medewerker” en “Afdeling”. De tabellen representeren de entiteiten die in een bepaald probleemdomein relevant zijn. Een bedrijf heeft vestigingen en vestigingen hebben medewerkers. De relatie tussen een medewerker en een vestiging noemen we in het dagelijks leven een dienstverband. Zo'n dienstverband kun je als een aparte entiteit modelleren. Helaas is er niet voor alle relaties tussen entiteiten een ingeburgerd begrip voorhanden. Het is dan ook niet echt gebruikelijk om zulke relaties als een entiteit te onderkennen.

Integrity Constraints zijn formele regels die erop gericht zijn om de consistentie tussen data in verschillende tabellen te bewaken. Stel dat een vestiging wordt gesloten; dan ligt het voor de hand dat er ook geen medewerkers meer in dienst zijn bij die betreffende vestiging. Met een constraint kun je voorkomen dat er medewerkers in de database voorkomen die een relatie (i.c. dienstverband) hebben met een vestiging die niet meer bestaat. Net zo goed kun je met zo'n constraint bewaken dat een valuta, bijvoorbeeld de gulden, niet verwijderd mag worden zolang er nog facturen in de database voorkomen die in guldens zijn opgesteld.

Tot zover gesneden koek. Appeltje eitje. Kind kan de was doen. Toch meen ik een fundamentele beperking in het relationele model op het spoor te zijn. En nog wel eentje die in heel veel systemen tot nodeloze complexiteit leidt of tot een vervelende beperking van de functionaliteit.

Wat mij namelijk al vele jaren verbaast is het ontbreken van het concept van tijdgebonden relaties in het relationele model – en vooral het gebrek aan discussie daarover. Het lijkt een impliciete aanname dat relaties tussen entiteiten altijd vast zijn. Toch zie ik in de praktijk heel veel relaties die je eerder vloeibaar zou kunnen noemen. Een paar voorbeelden.

  • Een bedrijf heeft gedurende een bepaalde periode een zekere vestiging

  • Een medewerker heeft gedurende een bepaalde periode een dienstverband met een vestiging van een bedrijf

  • Een medewerker heeft gedurende een bepaalde periode een bepaald salaris

En als je je er eenmaal bewust van bent, dan zie je ineens overal dit soort tijdgebonden relaties.

  • Een artikel heeft gedurende een bepaalde periode een prijs

  • Een artikel heeft ook gedurende een bepaalde periode een leverancier

  • Een artikel is gedurende een bepaalde periode in een assortimentsgroep ingedeeld.

Iedereen die wel eens te maken heeft gehad met het fenomeen terugwerkende kracht, of juist vooruitwerkende kracht, zal hoogstwaarschijnlijk tegen soortgelijke relaties zijn aangelopen. Wellicht dat hij of zij zich nog herinnert dat het best lastig is om dit soort relaties goed te modelleren. Ik ken zelfs mensen die spontaan in de stress schieten bij het horen van het woord peildatum.

model van de driehoeksrelatieNu is het op zich binnen het relationele model best te doen om een relatie tussen twee entiteiten tijdgebonden te maken. Wat je kunt doen is – in plaats van een enkelvoudige relatie tussen twee entiteiten – een driehoeksrelatie modelleren, waarbij in één entiteit de tijdvakken vastliggen die voor de relatie tussen de twee andere entiteiten gelden. Dus zoiets als in bijgaande afbeelding.

Er zit wel een klein nadeel aan zo'n constructie. Eenvoudige queries vertalen zich in SQL al snel in een behoorlijk ingewikkelde syntax met joins tussen de tabellen en conditionele where-clauses om af te testen of de begindatum van het dienstverband wel in het verleden ligt en de einddatum van het dienstverband ofwel nog niet is ingevuld, ofwel tenminste in de toekomst ligt. En gaat het nog maar om de simpele vraag naar een lijst met medewerkers per vestiging op een bepaald moment in de tijd. Zodra het iets ingewikkelder wordt, bijvoorbeeld de leverancier van een artikel (tijdvak 1) in een assortimentsgroep (tijdvak 2) per filiaal (tijdvak 3) op een bepaald moment in de tijd, dan heb je al te maken met drie verschillende tijdvakken, en evenzovele relatie-entiteiten, en explodeert een SQL query al snel tot tot een lengte die niet meer op een A4-tje past.

Zou het nou niet mogelijk zijn om SQL net iets slimmer te maken, om dit soort veel voorkomende relaties beter te ondersteunen? Zou het concept van tijdsnuggere relaties eigenlijk geen pijler onder het relationele model moeten zijn?


Om over te peinzen

Het is niet zo moeilijk om te bedenken hoe een tijdsnuggere SQL query er ongeveer uit zou moeten zien. Je zou al een eind in de richting kunnen komen met

SELECT *
FROM Medewerker
ON Datum
WHERE Salaris > 10.000
ORDER BY Geboortedatum;

Het is ook niet zo moeilijk om je voor te stellen dat een query preprocessor zo'n query automatisch zou kunnen expanderen naar een geldige SQL query met bijbehorende where clauses. En als we dan toch bezig zijn, dan weet ik er nog wel een paar. Neem nou de lijst met medewerkers uit het afgelopen jaar per filiaal

SELECT Medewerker.naam
FROM Filiaal, Medewerker
DURING (20070801; 20080731)
GROUP BY Filiaal;
*

Het kan toch niet zo moeilijk zijn om uit een dergelijke syntax eenduidig de conclusie te trekken dat het alleen om medewerkers gaat die in de opgegeven periode voor een filiaal hebben gewerkt? Of neem de lijst met omzet per maand van alle filialen die gedurende de gehele afgelopen 12 maanden omzet hebben gemaakt – de zogenaamde vergelijkbare omzet.

SELECT SUM (Omzet.bedrag)
FROM Filiaal, Omzet
DURING ALL (20070801; 20080731)
WHERE Omzet.datum >= 20070801
AND Omzet.datum <>
*

Deze is al een stukje lastiger te verwerken, omdat “ergens” de kennis vast moet liggen dat de during clause in dit geval ziet op het tijdvak dat het filiaal binnen het bedrijf actief was – dus iets betekent als

WHERE Filiaal.Startdatum <= 20070801 AND ( Filiaal.Einddatum >= 20080731
OR Filiaal.Einddatum = NULL)

En omdat dit nog relatief simpele voorbeelden zijn, zal het nog best het nodige denkwerk vereisen om een syntax te bedenken die in alle gevallen werkt. Toch ben ik er heilig van overtuigd dat er voor dit soort logische relaties ook een logische notatie te bedenken moet zijn. En dat het tijdvakconcept tot een standaard construct in relationele databases kan worden verheven. Het is wat mij betreft de hoogste tijd dat daar eens een degelijk proefschrift aan wordt gewijd.

Trouwens, als je er even over piekert, dan valt er op dit gebied nog veel meer te automatiseren. Stel je voert in dat een medewerker vanaf 1 januari een hoger salaris krijgt. Een slimme computer zou dan begrijpen dat dit automatisch betekent dat het lopende salaristijdvak moet worden afgesloten op 31 december – dit soort salarissen sluiten elkaar immers uit. Op dezelfde manier zou je kunnen bedenken dat als een medewerker benoemd wordt tot productmanager van een productgroep, deze rol voor de huidige medewerker ophoudt. Of als een artikel vanaf een bepaalde datum in een bepaalde assortimentsgroep valt, het niet meer in de huidige groep thuishoort. Ik zie dus veel potentie voor een automatisch gegenereerde tijdvakconstraint.

Zo'n automatisme geldt overigens niet voor alle relaties – niet alle relaties zijn mutually exclusive. Eén artikel kan op één moment in de tijd misschien best meerdere leveranciers hebben, net zo goed als één medewerker op één moment in de tijd best voor twee verschillende afdelingen kan werken. Aan de andere kant, een filiaal waar de laatste medewerker uit dienst gaat kan hoogstwaarschijnlijk gesloten worden, net zo goed als een artikel dat zijn laatste leverancier verliest best uit het assortiment genomen kan worden (of vice versa) en zo goed als voor een assortimentsgroep die wordt afgesloten alle tijdvakken van artikelen die aan die groep zijn gekoppeld best automatisch beëindigd zouden kunnen worden. In deze laatste gevallen zie ik nog een ander patroon, namelijk dat van de subperiode. Je kunt een algemene regel bedenken dat de periode van een dienstverband altijd moet vallen binnen de periode dat het organisatieonderdeel waarmee het wordt aangegaan bestaat. Of dat een prijs van een artikel alleen maar loopt binnen het tijdvak dat een artikel in het assortiment zit. Ook dergelijke tijdvakconstraints, die bij een UPDATE of een INSERT het leven aanzienlijk zouden kunnen vergemakkelijken, zouden relatief eenvoudig uit een tijdsnugger datamodel te genereren kunnen zijn. Maar dan moet er ook nog wel even een tijdsnuggere modelleertaal bedacht worden...

Mocht je door dit pleidooi geïnspireerd zijn geraakt, dan weet ik alvast een prikkelende stelling voor je proefschrift.

Het is de hoogste tijd dat de tijd dat SQL de tijd niet in de gaten had tot de verleden tijd gaat behoren.

Hora est.

Deze overpeinzing is bedoeld om tot nadenken te stemmen. Het is de 8ste in een reeks bespiegelingen die op dit weblog gepubliceerd zal worden.

* Deze voorbeelden zijn bewust gesimplificeerd.

[1] Codd, E.F: "A Relational Model of Data for Large Shared Data Banks"; Communications of the ACM 13 (6): 377–387, 1970.

1 opmerking:

Unknown zei

Hoi Hans,

Wellicht is dit een interessante om eens te lezen: http://www.amazon.com/Developing-Time-Oriented-Database-Applications-Management/dp/1558604367. Werd hier laatst zelf door iemand over getipt. Moet wel eerlijk bekennen dat ik het boek zelf nog niet gelezen heb ;-).