Het klinkt alsof je vooral bezig bent met prestaties.
Een paar mensen hebben voorgesteld om op te splitsen in 3 tabellen (categorietabel plus een eenvoudige kruisverwijzingstabel of een meer geavanceerde manier om de boomhiërarchie te modelleren, zoals een geneste set of een gematerialiseerd pad), wat het eerste is dat ik dacht toen ik uw vraag las .
Met indexen zal een dergelijke volledig genormaliseerde benadering (die twee JOIN's toevoegt) nog steeds "vrij goede" leesprestaties hebben. Een probleem is dat een INSERT of UPDATE van een gebeurtenis nu ook een of meer INSERT/UPDATE/DELETE's naar de kruisverwijzingstabel kan bevatten, wat op MyISAM betekent dat de kruisverwijzingstabel is vergrendeld en op InnoDB betekent dat de rijen zijn vergrendeld, dus als uw database bezig is met een aanzienlijk aantal schrijfbewerkingen, krijgt u grotere conflictproblemen dan wanneer alleen de gebeurtenisrijen waren vergrendeld.
Persoonlijk zou ik deze volledig genormaliseerde aanpak uitproberen voordat ik ga optimaliseren. Maar ik neem aan dat je weet wat je doet, dat je aannames correct zijn (categorieën veranderen nooit) en dat je een gebruikspatroon hebt (veel schrijfbewerkingen) dat vraagt om een minder genormaliseerde, platte structuur. Dat is helemaal prima en maakt deel uit van waar NoSQL over gaat.
SET vs. "veel kolommen"
Dus wat betreft uw eigenlijke vraag "SET vs. veel kolommen", kan ik zeggen dat ik heb gewerkt met twee bedrijven met slimme ingenieurs (wiens producten CRM-webapplicaties waren ... één was eigenlijk evenementenbeheer), en ze allebei gebruikte de "veel kolommen"-benadering voor dit soort statische setgegevens.
Mijn advies zou zijn om na te denken over alle zoekopdrachten die u op deze tabel gaat doen (gewogen op basis van hun frequentie) en hoe de indexen zouden werken.
Ten eerste, met de "veel kolommen"-benadering heb je indexen nodig op elk van deze kolommen, zodat je SELECT FROM events WHERE CategoryX = TRUE
. Met de indexen is dat een supersnelle zoekopdracht.
In tegenstelling tot SET moet u bitsgewijze AND (&), LIKE of FIND_IN_SET() gebruiken om deze query uit te voeren. Dat betekent dat de query geen index kan gebruiken en lineair moet zoeken in alle rijen (u kunt EXPLAIN gebruiken om dit te verifiëren). Langzame zoekopdracht!
Dat is de belangrijkste reden waarom SET een slecht idee is -- de index is alleen nuttig als je selecteert op exacte groepen categorieën. SET werkt prima als je categorieën per gebeurtenis selecteert, maar niet andersom.
Het belangrijkste probleem met de minder genormaliseerde "veel kolommen"-benadering (versus volledig genormaliseerd) is dat deze niet schaalt. Als je 5 categorieën hebt en ze veranderen nooit, prima, maar als je er 500 hebt en ze veranderen, is het een groot probleem. In jouw scenario, met ongeveer 30 die nooit veranderen, is het belangrijkste probleem dat er een index op elke kolom is, dus als je regelmatig schrijft, worden die zoekopdrachten langzamer vanwege het aantal indexen dat moet worden bijgewerkt. Als u voor deze aanpak kiest, wilt u misschien het MySQL-logboek voor trage zoekopdrachten controleren om er zeker van te zijn dat er op drukke tijden van de dag geen uitschieters zijn voor langzame zoekopdrachten vanwege onenigheid.
In jouw geval, als de jouwe een typische lees-zware web-app is, denk ik dat het waarschijnlijk verstandig is om te gaan met de "veel kolommen"-benadering (zoals de twee CRM-producten deden, om dezelfde reden). Het is zeker sneller dan SET voor die SELECT-query.
TL;DR Gebruik SET niet omdat de zoekopdracht "gebeurtenissen op categorie selecteren" traag zal zijn.