Wygląda na to, że interesuje Cię głównie wydajność.
Kilka osób zasugerowało podzielenie na 3 tabele (tabela kategorii plus prosta tabela odsyłaczy lub bardziej wyrafinowany sposób modelowania hierarchii drzewa, na przykład zestaw zagnieżdżony lub zmaterializowana ścieżka), co jest pierwszą rzeczą, o której pomyślałem, czytając twoje pytanie .
W przypadku indeksów takie w pełni znormalizowane podejście (dodające dwa sprzężenia) nadal będzie miało „całkiem dobrą” wydajność odczytu. Jednym z problemów jest to, że INSERT lub UPDATE do zdarzenia teraz może również zawierać jeden lub więcej INSERT/UPDATE/DELETE do tabeli odsyłaczy, co w MyISAM oznacza, że tabela odsyłaczy jest zablokowana, a w InnoDB oznacza, że wiersze są zablokowane. więc jeśli twoja baza danych jest zajęta znaczną liczbą zapisów, będziesz mieć większe problemy z rywalizacją, niż gdyby tylko wiersze zdarzeń były zablokowane.
Osobiście wypróbowałbym to w pełni znormalizowane podejście przed optymalizacją. Ale zakładam, że wiesz, co robisz, że twoje założenia są poprawne (kategorie nigdy się nie zmieniają) i masz wzorzec użycia (wiele zapisów), który wymaga mniej znormalizowanej, płaskiej struktury. To całkowicie w porządku i jest częścią tego, o co chodzi w NoSQL.
SET a „wiele kolumn”
Tak więc, jeśli chodzi o twoje pytanie "SET vs. wiele kolumn", mogę powiedzieć, że pracowałem z dwiema firmami z inteligentnymi inżynierami (którego produktami były aplikacje internetowe CRM ... jedna była właściwie zarządzaniem zdarzeniami) i obie zastosował podejście „wiele kolumn” dla tego rodzaju statycznych danych zestawu.
Radzę pomyśleć o wszystkich zapytaniach, które będziesz wykonywać w tej tabeli (ważonych według ich częstotliwości) oraz o tym, jak będą działały indeksy.
Po pierwsze, przy podejściu „wielu kolumn” będziesz potrzebować indeksów w każdej z tych kolumn, aby móc wykonać SELECT FROM events WHERE CategoryX = TRUE
. Z indeksami jest to superszybkie zapytanie.
W przeciwieństwie do SET, musisz użyć bitowego AND (&), LIKE lub FIND_IN_SET(), aby wykonać to zapytanie. Oznacza to, że zapytanie nie może używać indeksu i musi przeprowadzić liniowe przeszukiwanie wszystkich wierszy (możesz użyć polecenia EXPLAIN, aby to sprawdzić). Powolne zapytanie!
To jest główny powód, dla którego SET to zły pomysł — jego indeks jest użyteczny tylko wtedy, gdy wybierasz według dokładnych grup kategorii. SET działa świetnie, jeśli wybierasz kategorie według wydarzenia, ale nie na odwrót.
Podstawowym problemem związanym z mniej znormalizowanym podejściem „wielu kolumn” (w porównaniu z w pełni znormalizowanym) jest to, że nie skaluje się. Jeśli masz 5 kategorii i nigdy się nie zmieniają, to dobrze, ale jeśli masz 500 i je zmieniasz, to duży problem. W twoim scenariuszu, przy około 30, które nigdy się nie zmieniają, głównym problemem jest to, że w każdej kolumnie znajduje się indeks, więc jeśli wykonujesz częste zapisy, te zapytania stają się wolniejsze z powodu liczby indeksów, które muszą zostać zaktualizowane. Jeśli wybierzesz to podejście, możesz sprawdzić dziennik powolnych zapytań MySQL, aby upewnić się, że nie występują odstające powolne zapytania z powodu rywalizacji w ruchliwych porach dnia.
W twoim przypadku, jeśli twoja aplikacja jest typową aplikacją internetową o dużym obciążeniu odczytu, myślę, że pójście z podejściem „wielu kolumn” (tak jak dwa produkty CRM z tego samego powodu) jest prawdopodobnie rozsądne. Jest zdecydowanie szybciej niż SET dla tego zapytania SELECT.
TL;DR Nie używaj SET, ponieważ zapytanie „wybierz zdarzenia według kategorii” będzie powolne.