MySQL Возвращаясь к истокам
Описание: parent_id, parent_type, value
Краткое описание: parent_id, parent_type, value
Картинка: parent_id, parent_type, value
и т.п.
Уже выросло до 10 таблиц.
Построение было по принципу 3НФ. Но как то меня смущает количество. Оправдан ли такой подход? По 3НФ да, любое value может оказаться пустым, поэтому вынесено в отдельную таблицу. Но в итоге таблиц дофига, и сцепки в запросах получаются просто колоссальными...
С чего вы взяли, что именно это - 3НФ?
Почему бы не типизировать value?
Тогда все сведется к одной таблице, при этом поле типа также внести в первичный ключ.
Table1 (parent_id, parent_type, value_type, value)
Совершенно не оправдан. Ты смешиваешь сами данные и дерево для хранения эти данных. Данные (value и прочие поля) должны быть в одном месте, дерево (parent_id и сотоварищи) в другом.
У меня 7 таблиц позволяющих хранить и данные, и дерево и любые типы данных вообще. И новые таблицы заводить пока как-то не требуется.
научите
блин, не привык еще к этой клавиатуре. Расскажите как строть нормальные таблицы, у меня картинка в голове не складывается
Суть нормализации в том, чтобы избавиться от избыточности данных, т. е. от повторения одних и тех же данных в нескольких строках. Например, если Вы создаёте БД телефонный справочник, то гораздо разумнее будет связать таблицу "Город" с таблицей "Телефоны" (связь один-ко-многим: одной записи в таблице "Город" соответствует несколько записей в таблице "Телефоны"), чем писать название города 100500 раз в каждой строке, таким образом в таблице "Телефоны" будет ссылка на какой-то конкретный город. К тому же, если название города поменялось, то придётся его менять столько раз сколько телефонов в городе имеется, а в случае связи всего 1 раз в таблице "Город". С помощью связей также можно сделать каскадное обновление (обновление в главной и подчинённых таблицах) или удаление (удаление в главной и подчинённых таблицах) данных.
Нормальные формы: Первая НФ: каждое поле должно быть неделимым (атомарным). Это означает, что не должно быть таких полей, которые можно логически как-то разбить на несколько других полей. Например, поле ФИО содержит запись "Иванов Сергей Петрович", его можно разбить на 3 поля: фамилия, имя, отчество.
Вторая НФ: каждая запись таблицы должна однозначно определяться значением первичного ключа. Это значит, что не должно быть повторяющихся записей в таблице.
Третья НФ: в таблице не должно быть полей, значения которых зависят от значений неключевых полей. Например, в таблице "Товар" есть поля "Цена", "Количество", "Стоимость"; здесь поле "Стоимость" зависит от значений первых двух полей, поэтому его нужно удалить из таблицы: потом всегда можно будет сделать запрос с вычисляемым полем или добавить вычисляемое поле в набор данных.
стоит иногда грохнуть четыре базы чтобы понять что все не то и нетак, взял листик пошел чертить связку таблиц. в шесть я конечно не уложуся, но вроде до менянаконец дошло что мне нужно.
property(p_id, name, code, description, unit, is_multiple, value_type) - свойства объекта, к примеру "имя", "фамилия", "никнейм", поле unit - размерность свойства (метры, рубли и прочее), поле is_multiple это флаг того, что в таблице value может быть несколько строк, value_type всегда null и нужен только в особых случах (модуль с фалами, см. ниже);
object_property(op_id, o_id, p_id, property_code) - линковочная таблица связей между object и property, где property_code это копия из property.code и это пример демормализации, необходима что бы строить уникальный индекс по (o_id, property_code), т.е. контроль на уровне БД, что у одного объекта не может быть двух одинаковых свойств;
item(i_id, o_id) - конкретный "экземляр" объекта, аналогично отношению из ООП как класс-экземляр_класса;
value(v_id, op_id, i_id, value) - конкретное значение для свойства объекта с идентификатором op_id, при этом value это поле с банальным типом text, причем на нем НЕТ индекса;
category(c_id, name, code, decsription, parent_id) - обычное дерево в виде Adjacency List;
category_object(co_id, c_id, o_id) - линковочная таблица связи листа дерева и объекта;
Если завтра меня не устроит AL и понадобиться Nested Sets, то структура category будет изменена под NS, но это изменение не затронет даже category_object. Данные отдельно, дерево отдельно.
У меня может быть любое количество объектов с любым количеством свойств, при этом ни код, ни структура таблица совершенно ни как не изменяются. Если завтра у "пользователь" мне потребуется свойство "номер телефона бабушки отца третьего колена", то все, что потребуется, это доработать шаблоны страницы профайла юзера, код работающий с самой базой это ни как не затронет.
Указанный подход не покрывает всех задач веба, но реализует огромную его часть. Специфичные же случае очень просто допиливаются на текущую структуру. К примеру, если мне нужен индекс на value (для модуля работы с файлами где value это md5 хэш от url с которого был скачан этот файл, т.е. очень много запросов на поиск конкретного хэша), то я просто наследую от value таблицы (ибо в меня postgresql) новую таблицу в которой есть поле value_hash, а property.value_type=value_hash (т.е. данные из таблицы value брать не из поля value, а из value_hash). На value_hash вещается индекс. Код работы с базой опять таки это ни как не затрагивает, он по прежнему остается неизменным. При этом унаследованная таблица это физически новая таблица и в ней свой собственный идекс независимый от value таблицы. Поэтому у меня нет пустых полей, у меня база не распухает от кучи индексов. Эта допилка покрывает все остальные нужны, поэтому схему считаю универсальной.
Цитата: SibBear
...Нормальные формы...
Денормализация как и нормализация один из подходов в разработке. Не всегда данные в нормальной форме это адекватная структура БД. Денормализация так же важна. Это приходит с опытом.
Спасибо большое, EAV архитектура это вещь.