В случае простых атомных значений я склонен не соглашаться с общей мудростью в этом вопросе, главным образом в отношении сложности. Рассмотрим таблицу с шляпами. Вы можете сделать «денормализованный» способ:
CREATE TABLE Hat (
hat_id INT NOT NULL PRIMARY KEY,
brand VARCHAR(255) NOT NULL,
size INT NOT NULL,
color VARCHAR(30) NOT NULL /* color is a string, like "Red", "Blue" */
)
Или вы можете нормализовать его, сделав таблицу "color":
CREATE TABLE Color (
color_id INT NOT NULL PRIMARY KEY,
color_name VARCHAR(30) NOT NULL
)
CREATE TABLE Hat (
hat_id INT NOT NULL PRIMARY KEY,
brand VARCHAR(255) NOT NULL,
size INT NOT NULL,
color_id INT NOT NULL REFERENCES Color(color_id)
)
Конечным результатом последнего является то, что вы добавили некоторую сложность - вместо:
SELECT * FROM Hat
Теперь вы должны сказать:
SELECT * FROM Hat H INNER JOIN Color C ON H.color_id = C.color_id
Это дополнительное присоединение к огромной сделке? Нет, на самом деле это основа реляционной модели проектирования - нормализация позволяет предотвратить возможные несоответствия в данных. Но каждая такая ситуация добавляет немного сложности, и если нет веских причин, стоит спросить, почему вы это делаете. Я считаю возможные "веские причины" включать:
- Существуют ли другие атрибуты, которые "зависают" от этого атрибута? Вы захватываете, скажем, и "имя цвета", и "шестнадцатеричное значение", так что шестнадцатеричное значение всегда зависит от имени цвета? Если это так, то вам определенно нужна отдельная таблица цветов, чтобы предотвратить ситуации, когда одна строка имеет («Красный», «# FF0000»), а другая - («Красный», «# FF3333»). Множественные коррелированные атрибуты являются сигналом № 1 о том, что объект должен быть нормализован.
- Будет ли набор возможных значений часто меняться? Использование нормализованной таблицы поиска облегчит будущие изменения элементов набора, поскольку вы просто обновляете одну строку. Однако, если это нечасто, не отказывайтесь от операторов, которые вместо этого должны обновлять множество строк в основной таблице; базы данных довольно хороши в этом. Если вы не уверены, проведите несколько тестов скорости.
- Будет ли пользователь напрямую управлять набором возможных значений? Т.е. Есть ли экран, где они могут добавить / удалить / изменить порядок элементов в списке? Если так, то отдельная таблица обязательна.
- Будет ли список различных значений влиять на некоторый элемент пользовательского интерфейса? Например. такое «цвет» в выпадающем списке? Тогда вам лучше иметь его в отдельной таблице, а не делать SELECT DISTINCT для таблицы каждый раз, когда вам нужно отобразить выпадающий список.
Если ни один из них не применим, мне будет трудно найти другую (хорошую) причину для нормализации. Если вы просто хотите убедиться, что значение является одним из определенного (небольшого) набора допустимых значений, вам лучше использовать CONSTRAINT, который говорит, что значение должно быть в определенном списке; все упрощается, и вы всегда можете «перейти» на отдельную таблицу позже, если возникнет такая необходимость.