Эволюционирующая схема БД

28
Эволюционирующая схема БД Sustainable Database Schema Interlabs 14 февраля 2014 1 / 28

Post on 07-Dec-2014

702 views

Category:

Technology


3 download

DESCRIPTION

Как сделать схему базы данных приложения более универсальной? Что можно сделать на уровне схемы для того, чтобы сделать ее более адаптируемой к изменениям ТЗ по мере развития проекта? Какие стереотипы при проектировании схемы мешают достижению этих задач?

TRANSCRIPT

Page 1: Эволюционирующая схема БД

Эволюционирующая схема БДSustainable Database Schema

Interlabs

14 февраля 2014

1 / 28

Page 2: Эволюционирующая схема БД

Что мы хотим

• единая базовая схема для различных проектов• компонуемая из отдельных функциональных блоков• адаптируемая к особенностям проекта• эволюционирующая вместе с проектом• эволюционно масштабируемая и оптимизируемая• самодостаточная, не требующая для работыдополнительных клиентских средств

Sustainable Database Schema

2 / 28

Page 3: Эволюционирующая схема БД

Сферический проект в вакууме• набор различных типов сущностей с собственныматрибутным составом: продукты, страницы, новости, теги ит.д.

• семантические связи между сущностями• в том числе — таксономия: группы товаров, теговаяклассификация и т.д.

• часто — произвольный набор свойств (E.A.V.) длянекоторых типов: свойства продуктов, товарныхпредложений и т.д.

• различные типовые сервисы: комментарии, рейтинги,контент и т.д.

Сущности + связи + таксономия +наборы свойств + общие сервисы

3 / 28

Page 4: Эволюционирующая схема БД

Тривиальная схемаКаждая сущность в отдельной таблице с AUTO_INCREMENT.

Сущности изолированы внутри таблиц за счетлокальности идентификатора.

4 / 28

Page 5: Эволюционирующая схема БД

Проблемы тривиальной схемы• сложность реализации общих универсальных сервисов:комментирование и рейтингование сущностей, поиск посайту и т.д.

• сложность построения связей между разнороднымисущностями: с этим товаром покупают, новости о товаре,читай также и т.д.

• EAV-поля для разнородного контента (если нужен EAV).

Главная проблема: своя последовательность idдля каждого типа

• нельзя однозначно идентифицировать сущность• нельзя сослаться на произвольную сущность

5 / 28

Page 6: Эволюционирующая схема БД

Глобальный идентификатор• единая последовательность для всех сущностей;• глобальность id определяется алгоритмом генерации• ссылочная целостность — общая таблица сущностей

6 / 28

Page 7: Эволюционирующая схема БД

Таблица сущностей

• заполняется автоматически при вставке в частные таблицы• type определяет тип сущности, можно использовать ENUM;• внешние ключи с частных таблиц — каскадное удалениепри удалении из общей таблицы;

• дополнительные триггеры на удаление из частных таблиц;• если необходимо — дополнительные поля,характеризующие сущность в целом (даты создания иизменения, права доступа и т.д.)

Если таблица ведется полностью автоматически, можноиспользовать даже на legacy-проектах.

7 / 28

Page 8: Эволюционирующая схема БД

Общая структура

Общий аспект сущностей = отдельная таблица.

8 / 28

Page 9: Эволюционирующая схема БД

Общая структура

• наличие единой последовательности id позволяет легкорасширять функциональность сущностей;

• у разных видов сущностей могут быть общие аспекты:отображаемый ресурс, результат поиска, категория и т.д.);

• факт наличия сущности в таблице определяет наличие унее соответствующего аспекта;

• если необходимо, таблица аспекта может содержать поле стипом сущности для упрощения обработки;

• общие сервисы используют общую таблицу сущностей дляссылочной целостности.

9 / 28

Page 10: Эволюционирующая схема БД

Генерация общего idAUTO_INCREMENT в entity

• уникален в пределах набора таблиц, последователен• клиент без изменений кроме непосредственно вставки• наиболее подходящий вариант для legacy проектов

UUID_SHORT()

• глобально уникален, последователен• теоретически подходит для миграции данных• можно использовать вообще для всех таблиц• необходима поддержка на уровне клиентского кода• помним о размерности int на клиенте

10 / 28

Page 11: Эволюционирующая схема БД

AUTO_INCREMENT в entity• перед вставкой в рабочую таблицу — вставка в entity• используем полученный id в качестве первичного ключадля рабочей таблицы

Как получить id на клиенте?

LAST_INSERT_ID больше не подходит, поэтому либо:

• два INSERT со стороны клиента, первый возвращает id• хранимая процедура на сервере, выполняет два INSERT,возвращает id в качестве результирующей выборки.

11 / 28

Page 12: Эволюционирующая схема БД

UUID_SHORT()Триггер BEFORE INSERT в рабочей таблице:

IF NOT ‘NEW‘.‘id‘ THENSET ‘NEW‘.‘id‘ = UUID_SHORT();INSERT INTO ‘entity‘(‘id‘, ‘type‘) VALUES( ‘NEW‘.‘id‘, ’PRODUCT’);

END IF;

• на клиенте явно получаем UUID_SHORT() и используем привставке в рабочую таблицу;

• при работе с базой напрямую просто делаем вставку,entity заполняется автоматически.

12 / 28

Page 13: Эволюционирующая схема БД

Связи между сущностямиЧем более семантически связен контент, тем больше связеймежду различными сущностями:

товар принадлежит категории, с этим товаром покупают, другие товарыбренда, аналоги товара, новости про этот товар и т.д.

• максимум возможных связей при минимальной схеме• ссылочная целостность и каскадное удаление дляупрощения клиента

Нужно описывать связи на общем уровне.

13 / 28

Page 14: Эволюционирующая схема БД

Таблица связей

14 / 28

Page 15: Эволюционирующая схема БД

Таблица связей

• type определяет вид связи (проще всего — ENUM)• sourceType и targetType дублируют типы сущностей• внешний ключ по id и типу — ссылочная целостность• поля типов могут быть использованы для контролядопустимости отношения триггером

• каскадное удаление отношений при удалении сущностей• наличие таблицы связей не означает, что все cвязи нужноустанавливать через эту таблицу

• однако автоматическое дублирование связей вида 1→Nможет быть полезно, если по мере развития проекта онипревращаются в M→N.

15 / 28

Page 16: Эволюционирующая схема БД

Связи 1→ NНаличие таблицы связей не означает, что все связи через нее:

• постановка предусматривает 1→ N между сущностями —работаем с ссылочным полем

• есть шанс, что со временем отношение станет N→ M —автоматически дублируем отношение в таблице связей

Результат: ничего не теряем с точки зрения сложности клиента,получаем страховку на случай смены ТЗ, иногда выгоднотрактовать ссылку как общее отношение.

ДА товар→ группа товаров.НЕТ товарное предложение→ товар.

16 / 28

Page 17: Эволюционирующая схема БД

ТаксономияСущности классифицируются другими сущностями, например:

• группы товаров• производители товаров• теги (для всех видов сущностей) и т.д.

Много различных вариантов категоризации по мере развитияпроекта, поэтому реализуем на общем уровне:

• категория — вид сущности (таблицы entity + category)• древовидность в таблице category• связь N→ M через relations• категория — аспект сущности• принадлежность категории — отношение

17 / 28

Page 18: Эволюционирующая схема БД

Таксономия

18 / 28

Page 19: Эволюционирующая схема БД

Entity Attribute Value

• для данных фиксированной структуры всегда используемобычные таблицы, часто выгодно вынести отдельныйаспект данных в отдельную таблицу

• используем EAV когда это действительно нужно (например,каталог товаров)

• не привязываем EAV к конкретному виду сущности —никогда не знаешь, что будет потом

• эффективный поиск — с использованием Sphinx

EAV — общий сервис для всех сущностей

19 / 28

Page 20: Эволюционирующая схема БД

Универсальный EAV

20 / 28

Page 21: Эволюционирующая схема БД

EAV: атрибуты

NUM число, STR строка, DAT дата, REF справочник

• четырех типов достаточно, например, для импортаCommerceML

• для каждого типа — свое поле для хранения значения• другие поля — для денормализации, если это имеет смысл• атрибуты нужно группировать в наборы для облегченияадминистрирования

• набор атрибутов — категория, отношение «категория→атрибут» — 1→ N или N→ M

21 / 28

Page 22: Эволюционирующая схема БД

EAV: ссылочные атрибуты

Наличие значения ссылочного атрибута =классификация по этому значению

• значение ссылочного атрибута — сущность• значение ссылочного атрибута — категория, привязанная катрибуту (дополнительное поле в category)

• category — справочник атрибутов• установка ссылочного атрибута дублируется в relation

Две точки зрения на ссылочный атрибут: значение свойства(attribute_value) и классификация (relation).

22 / 28

Page 23: Эволюционирующая схема БД

Фасетный поискТаксономия: индекс Sphinx c MVA-атрибутом по таблице

relationsАтрибуты: индекс Sphinx с JSON-атрибутами по таблице

attribute_value

• для ссылочных атрибутов можно обойтись одниминдексом по relation

• числовые атрибуты может быть выгодно преобразовать вссылочные, разбив значения на диапазоны.

Единая трактовка таксономии и ссылочных атрибутов можетупростить поиск.

23 / 28

Page 24: Эволюционирующая схема БД

Счетчики и каскадКаскадное удаление существенно упрощает клиент, но нужноиспользовать осмотрительно, избыточный cascade можетвычистить половину базы:

delete="cascade"

Для удаления элементовсущности: значения атрибутовсущности, отношениясущности.

delete="restrict"

Для запрета удалениясвязанных сущностей: группыили бренда при наличиитоваров и т.д.

Проблема: без дополнительных запросов определить наличиеrestrict на клиенте, для блокировки действия.

24 / 28

Page 25: Эволюционирующая схема БД

Поле счетчика

• должно заполняться автоматически триггерами• для 1→ N есть стандартное расширение в baser:

<Table name="comment_reply" comment="Комментарии"><Column name="thread" type="&id;" comment="Тред"/><ForeignKey name="thread" table="thread"

comment="ссылка на тред"ext:count="numOfReplies" <- триггеры генерируются автоматически> 25 / 28

Page 26: Эволюционирующая схема БД

API схемыБаза должна быть самодостаточна, поэтому:

• типовые операции, не укладывающиеся в одноSQL-выражение, выносим в хранимые процедуры;

• периодическое обслуживание базы (архивирование,удаление неактуальных данных и т.д.) выносим в events;

• весь хранимый код формирует API схемы, в будущем —документируемый средставами baser;

• API — не только для приложения, но и для человека,работающего с базой руками.

Иногда реализация хранимой — способ избежать большихизменений на legacy-клиентах (пример с хранимой длясоздания сущности).

26 / 28

Page 27: Эволюционирующая схема БД

Использование baser• проще писать большое количество хранимого кода• часть хранимого кода и структуры генерируетсяавтоматически расширениями

• можно (и нужно!) унифицировать определения типовданных внутри схемы:

<!DOCTYPE Schema [<!ENTITY entities "ENUM(’PRODUCT’, ’CATEGORY’, ’FAQ’, ’FILE’, ’NEWS’)"><!ENTITY attributes "ENUM(’NUM’, ’STR’, ’DAT’, ’REF’)"><!ENTITY id "MEDIUMINT UNSIGNED"><!ENTITY name "VARCHAR(255)">

]>...

<Column name="type" type="&entities;" ... /><Column name="name" type="&name;" .../>

...

27 / 28

Page 28: Эволюционирующая схема БД

Итого

• небольшой базовый набор концепций, расширяющийтрадиционную схему, повышает ее приспособляемость кизменениями ТЗ;

• AUTO_INCREMENT — удобный антипаттерн;• важно мыслить не сущностями в целом, а суммой ихотдельных аспектов;

• даже для legacy-проектов можно извлечь выгоду, вчастности, при организации поиска;

• элементы CMS могут быть реализованы непосредственно вбазе без, собственно, CMS.

28 / 28