Zdá se, že vám jde především o výkon.
Několik lidí navrhlo rozdělení do 3 tabulek (tabulka kategorií plus buď jednoduchá tabulka křížových odkazů, nebo sofistikovanější způsob modelování stromové hierarchie, jako je vnořená množina nebo materializovaná cesta), což je první věc, kterou jsem si pomyslel, když jsem četl vaši otázku. .
S indexy bude mít takový plně normalizovaný přístup (který přidá dva JOINy) stále "docela dobrý" výkon při čtení. Jedním z problémů je, že INSERT nebo UPDATE události nyní může také zahrnovat jeden nebo více INSERT/UPDATE/DELETE do tabulky křížových odkazů, což na MyISAM znamená, že tabulka křížových odkazů je uzamčena a na InnoDB znamená, že řádky jsou uzamčeny, takže pokud je vaše databáze zaneprázdněna značným počtem zápisů, budete mít větší problémy se spory, než kdyby byly uzamčeny pouze řádky událostí.
Osobně bych tento plně normalizovaný přístup před optimalizací vyzkoušel. Ale budu předpokládat, že víte, co děláte, že vaše předpoklady jsou správné (kategorie se nikdy nemění) a máte vzor použití (spousta zápisů), který vyžaduje méně normalizovanou, plochou strukturu. To je naprosto v pořádku a je to součástí toho, o čem NoSQL je.
SET vs. "spousta sloupců"
Takže, pokud jde o vaši aktuální otázku „SET vs. spousta sloupců“, mohu říci, že jsem spolupracoval se dvěma společnostmi s chytrými inženýry (jejichž produkty byly webové aplikace CRM... jedním bylo ve skutečnosti řízení událostí) a oba pro tento druh statických dat sady použil přístup „spousta sloupců“.
Moje rada je zamyslet se nad všemi dotazy, které budete v této tabulce provádět (váženo jejich frekvencí) a jak by indexy fungovaly.
Za prvé, s přístupem "spousta sloupců" budete potřebovat indexy pro každý z těchto sloupců, abyste mohli provést SELECT FROM events WHERE CategoryX = TRUE
. S indexy je to superrychlý dotaz.
Na rozdíl od SET musíte k provedení tohoto dotazu použít bitové AND (&), LIKE nebo FIND_IN_SET(). To znamená, že dotaz nemůže používat index a musí provádět lineární vyhledávání všech řádků (k ověření můžete použít EXPLAIN). Pomalý dotaz!
To je hlavní důvod, proč je SET špatný nápad – jeho index je užitečný pouze v případě, že vybíráte podle přesných skupin kategorií. SET funguje skvěle, pokud byste vybírali kategorie podle události, ale ne naopak.
Primárním problémem méně normalizovaného přístupu „spousta sloupců“ (oproti plně normalizovanému) je to, že se neškáluje. Pokud máte 5 kategorií a nikdy se nemění, dobře, ale pokud jich máte 500 a měníte je, je to velký problém. Ve vašem scénáři s přibližně 30, které se nikdy nemění, je primární problém, že v každém sloupci je index, takže pokud provádíte časté zápisy, tyto dotazy se zpomalí kvůli počtu indexů, které je třeba aktualizovat. Pokud zvolíte tento přístup, možná budete chtít zkontrolovat protokol pomalých dotazů MySQL, abyste se ujistili, že zde nejsou odlehlé pomalé dotazy kvůli sporům v rušnou denní dobu.
Ve vašem případě, pokud je vaše typická webová aplikace náročná na čtení, myslím, že jít s přístupem „spousta sloupců“ (jako dva produkty CRM ze stejného důvodu) je pravděpodobně rozumné. Je to určitě rychlejší než SET pro daný dotaz SELECT.
TL;DR Nepoužívejte SET, protože dotaz „vyberte události podle kategorie“ bude pomalý.