Det lyder som om, du primært er optaget af ydeevne.
Et par personer har foreslået at opdele i 3 tabeller (kategoritabel plus enten simpel krydsreferencetabel eller en mere sofistikeret måde at modellere træhierarkiet på, såsom indlejret sæt eller materialiseret sti), hvilket er det første jeg tænkte, da jeg læste dit spørgsmål .
Med indekser vil en sådan fuldt normaliseret tilgang (som tilføjer to JOINs) stadig have "temmelig god" læseydelse. Et problem er, at en INSERT eller OPDATERING til en begivenhed nu også kan inkludere en eller flere INSERT/UPDATE/DELETEs til krydsreferencetabellen, hvilket på MyISAM betyder, at krydsreferencetabellen er låst, og på InnoDB betyder, at rækkerne er låst, så hvis din database er optaget af et betydeligt antal skrivninger, vil du få større konfliktproblemer, end hvis blot begivenhedsrækkerne var låst.
Personligt ville jeg prøve denne fuldt normaliserede tilgang, før jeg optimerede. Men jeg antager, at du ved, hvad du laver, at dine antagelser er korrekte (kategorier ændres aldrig), og du har et brugsmønster (masser af skrivninger), der kræver en mindre normaliseret, flad struktur. Det er helt fint og er en del af det, NoSQL handler om.
SET vs. "masser af kolonner"
Så med hensyn til dit egentlige spørgsmål "SET vs. masser af kolonner", kan jeg sige, at jeg har arbejdet med to virksomheder med smarte ingeniører (hvis produkter var CRM-webapplikationer ... den ene var faktisk begivenhedsstyring), og de begge brugt "masser af kolonner"-tilgangen til denne slags statiske datasæt.
Mit råd ville være at tænke over alle de forespørgsler, du vil lave på denne tabel (vægtet efter deres hyppighed), og hvordan indekserne ville fungere.
For det første skal du med "masser af kolonner"-tilgangen have brug for indekser på hver af disse kolonner, så du kan udføre SELECT FROM events WHERE CategoryX = TRUE
. Med indekserne er det en superhurtig forespørgsel.
I modsætning til SET skal du bruge bitvis AND (&), LIKE eller FIND_IN_SET() for at udføre denne forespørgsel. Det betyder, at forespørgslen ikke kan bruge et indeks og skal lave en lineær søgning af alle rækker (du kan bruge EXPLAIN til at bekræfte dette). Langsom forespørgsel!
Det er hovedårsagen til, at SET er en dårlig idé - dets indeks er kun nyttigt, hvis du vælger efter nøjagtige grupper af kategorier. SET fungerer godt, hvis du vil vælge kategorier efter begivenhed, men ikke omvendt.
Det primære problem med den mindre normaliserede tilgang med "masser af kolonner" (versus fuldt normaliseret) er, at den ikke skaleres. Hvis du har 5 kategorier, og de ændrer sig aldrig, fint, men hvis du har 500 og ændrer dem, er det et stort problem. I dit scenarie, med omkring 30, der aldrig ændrer sig, er det primære problem, at der er et indeks på hver kolonne, så hvis du skriver hyppigt, bliver disse forespørgsler langsommere på grund af antallet af indekser, der skal opdateres. Hvis du vælger denne tilgang, vil du måske tjekke MySQL's langsomme forespørgselslog for at sikre dig, at der ikke er afvigende langsomme forespørgsler på grund af uenighed på travle tidspunkter af dagen.
I dit tilfælde, hvis din er en typisk læsetung web-app, tror jeg, at det sandsynligvis er fornuftigt at bruge "masser af kolonner"-tilgangen (som de to CRM-produkter gjorde, af samme grund). Det er helt sikkert hurtigere end SET for den SELECT-forespørgsel.
TL;DR Brug ikke SET, fordi "vælg begivenheder efter kategori"-forespørgslen vil være langsom.