Strevend naar een optimaal DB-ontwerp (mysql 5.0) voor een voorraadsysteem loop ik tegen een dilemma aan. Ik ben op zoek naar een oplossing die snel (<1sec/q) werkt met zeg 10.000 records, moeilijk of niet in een inconsistente staat te brengen is en die geen data (drie/vier/etc-)dubbel opslaat.
In de vereenvoudiging van het probleem heb ik twee tabellen. In de tabel 'partij' staat per record een partij die een referentienummer en nog een aantal vaste kenmerken heeft. In de tabel 'mutatie' staan mutaties die invloed hebben op een partij, zoals het veranderen van eigenaar of het aanpassen van de locatie of hoeveelheid. Bij veel mutaties verandert slechts één van de eigenschappen van de partij. De kolommen van eigenschappen die onveranderd blijven staan op NULL.
MySQL Workbench maakt er het volgende plaatje van:

Dit lijkt me de meest efficiënte vorm van opslag, maar levert met het raadplegen wat problemen op. Ik wil een overzicht kunnen maken van alle partijen en daarbij per partij de huidige eigenaar, locatie en hoeveelheid tonen. Doordat de mutaties op de hoeveelheid relatief zijn, kan ik met een simpele join en een sum() wel de hoeveelheid tonen, maar de eigenaar en locatie zijn lastiger tevoorschijn te halen zonder een afhankelijke subquery te gebruiken en daarmee performance in te leveren.
De eerste semi-oplossing is om door de applicatie of eventueel triggers de huidige eigenaar en locatie ook in de partij-tabel op te slaan. Dat past echter niet bij een correct database-ontwerp en het kan bovendien voorkomen dat de voorraad op een bepaalde datum moet worden opgemaakt. De extra gegevens in de partij-tabel zijn dan zinloos en de juiste eigenaar op die datum moet alsnog uit de mutatie-tabel worden gehaald.
De tweede oplossing is om in de mutatie-tabel altijd alle kolommen te vullen. Een mutatie waarbij slechts de eigenaar verandert zal dan ook de locatie bevatten die op dat moment voor de partij geldt. Doordat de hoeveelheid relatief is, kan die natuurlijk wel op 0 blijven. Het probleem hierbij is, dat het tussenvoegen van een mutatie nogal wat werk oplevert en de database makkelijk in een inconsistente staat kan worden gebracht. Bij het tussenvoegen van een mutatie moet dan van een aantal volgende mutaties bijvoorbeeld de eigenaar worden aangepast. Hetzelfde geldt voor het verwijderen van een mutatie.
Er zijn natuurlijk meer lelijke oplossingen te bedenken, maar een nette heb ik nog niet kunnen vinden. Wat zie ik hierbij over het hoofd ? Ik kwam vragen bij het zoeken wel vragen van mensen tegen die een LAST() of FIRST() aggregate function willen, maar dat zit nu eenmaal niet in MySQL en naar ik begreep moeten ook de meeste andere RDBMSen het zonder doen.
In de vereenvoudiging van het probleem heb ik twee tabellen. In de tabel 'partij' staat per record een partij die een referentienummer en nog een aantal vaste kenmerken heeft. In de tabel 'mutatie' staan mutaties die invloed hebben op een partij, zoals het veranderen van eigenaar of het aanpassen van de locatie of hoeveelheid. Bij veel mutaties verandert slechts één van de eigenschappen van de partij. De kolommen van eigenschappen die onveranderd blijven staan op NULL.
MySQL Workbench maakt er het volgende plaatje van:

Dit lijkt me de meest efficiënte vorm van opslag, maar levert met het raadplegen wat problemen op. Ik wil een overzicht kunnen maken van alle partijen en daarbij per partij de huidige eigenaar, locatie en hoeveelheid tonen. Doordat de mutaties op de hoeveelheid relatief zijn, kan ik met een simpele join en een sum() wel de hoeveelheid tonen, maar de eigenaar en locatie zijn lastiger tevoorschijn te halen zonder een afhankelijke subquery te gebruiken en daarmee performance in te leveren.
De eerste semi-oplossing is om door de applicatie of eventueel triggers de huidige eigenaar en locatie ook in de partij-tabel op te slaan. Dat past echter niet bij een correct database-ontwerp en het kan bovendien voorkomen dat de voorraad op een bepaalde datum moet worden opgemaakt. De extra gegevens in de partij-tabel zijn dan zinloos en de juiste eigenaar op die datum moet alsnog uit de mutatie-tabel worden gehaald.
De tweede oplossing is om in de mutatie-tabel altijd alle kolommen te vullen. Een mutatie waarbij slechts de eigenaar verandert zal dan ook de locatie bevatten die op dat moment voor de partij geldt. Doordat de hoeveelheid relatief is, kan die natuurlijk wel op 0 blijven. Het probleem hierbij is, dat het tussenvoegen van een mutatie nogal wat werk oplevert en de database makkelijk in een inconsistente staat kan worden gebracht. Bij het tussenvoegen van een mutatie moet dan van een aantal volgende mutaties bijvoorbeeld de eigenaar worden aangepast. Hetzelfde geldt voor het verwijderen van een mutatie.
Er zijn natuurlijk meer lelijke oplossingen te bedenken, maar een nette heb ik nog niet kunnen vinden. Wat zie ik hierbij over het hoofd ? Ik kwam vragen bij het zoeken wel vragen van mensen tegen die een LAST() of FIRST() aggregate function willen, maar dat zit nu eenmaal niet in MySQL en naar ik begreep moeten ook de meeste andere RDBMSen het zonder doen.