27
Работа со схемой БД в проектах Interlabs 17 декабря 2013 1 / 27

Ведение схемы БД в проектах

  • View
    547

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Ведение схемы БД в проектах

Работа со схемой БД в проектах

Interlabs

17 декабря 2013

1 / 27

Page 2: Ведение схемы БД в проектах

Миграции

Первое, о чем все говорят, когда речь заходит о работе с базой:

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

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

2 / 27

Page 3: Ведение схемы БД в проектах

Миграции: пример

use DoctrineDBALMigrationsAbstractMigration,DoctrineDBALSchemaSchema;

class Version20130112132011 extends AbstractMigration {public function up(Schema $schema) {

$this->addSql( "CREATE TABLE ...");}

public function down(Schema $schema) {$this->addSql("DROP TABLE ...");

}}

3 / 27

Page 4: Ведение схемы БД в проектах

Миграции: плюсы и минусы

• могут генерироваться автоматически (в т.ч. по diff)• можно использовать API для типовых операций• универсально для разных серверов БД

В то же время:

• в основном решает только задачу модификации схемы• компоновка из стандартных модулей — ООП-сценарий• документирование и визуализация — отдельная задача• хранимый код и view — неудобно, база = набор таблиц.

4 / 27

Page 5: Ведение схемы БД в проектах

Что мы хотим?//////////Ничего.• простой формат описания схемы, низкий порог вхождения• миграции на SQL• набор преобразований описания в различные форматы —HTML документация, SVG для диаграмм, SQL для миграций

• возможность компоновки схемы из стандартных модулей• поддержка библиотеки стандартных триггеров,расширяющих поведение объектов базы

• минимум зависимостей

Все банально, хотя сейчас уже не модно:

XML→ XSL→ SQL, SVG, HTML . . .

5 / 27

Page 6: Ведение схемы БД в проектах

Это миграции?

• нет, это описание схемы на определенный момент• но с помощью этого мы можем сгенерировать код длямиграций

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

• не работаем непосредственно с базой, хотя описаниеможет быть сгенерировано из существующей базы

• миграция данных — вручную

6 / 27

Page 7: Ведение схемы БД в проектах

Почему XML?

Simplest Thing Possible

• не очень удобно писать руками, но жить можно• легко валидировать• легко преобразовывать в различные форматы• легко расширять• легко написать прототип в виде набора XSL-стилей• может быть легко сгенерирован по реальной базе

database.xml7 / 27

Page 8: Ведение схемы БД в проектах

database.xml<Database>

<Description><p>Демонстрация database.xml.</p>

</Description><Table name="test" comment="Тестовая таблица">

<Description><p>Подробное описание тестовой таблицы.</p>

</Description><Column name="id" type="bigint" primary="true" /><Column name="title" type="varchar" size="255" comment="Имя" /><Index name="title" comment="Сортировка по имени">

<IndexColumn name="title" /></Index><Trigger when="before" action="insert">

<SQL>SET NEW.id = UUID_SHORT();</SQL></Trigger>

</Table></Database>

8 / 27

Page 9: Ведение схемы БД в проектах

ТаблицаИспользуем разумные умолчания (ENGINE=InnoDB), требуемналичия описания.

<Table Определение таблицы:name="имя" - имя таблицыcomment="комментарий" - комментарий, сохраняемый в базе>

Элементы таблицы в любом порядке:<Column ../> - колонка<Index ../> - индекс<ForeignKey ../> - внешний ключ<Trigger ../> - триггер

</Table>

9 / 27

Page 10: Ведение схемы БД в проектах

КолонкаИспользуем разумные умолчания (NOT NULL), требуем наличияописания.

<Column Определение колонки:name="имя" - имя колонкиtype="тип" - тип данных MySQLsize="размер" - необязательный размерdefault="значение" - значение по умолчаниюprimary="true|false" - использование в PRIMARY KEYnull="true|false" - по умолчанию всегда NOT NULLcomment="комментарий" - сохраняемый в базе комментарий/>

10 / 27

Page 11: Ведение схемы БД в проектах

ИндексДля уникальных индексов генерируется CONSTRAINT.

<Index Определение индекса:name="имя" - имя индексаunique="true|false" - уникальный индексcomment="комментарий" - сохраняемый в базе комментарий>

<IndexColumn Определение колонки индекса:name="имя" - имя колонкиdesc="true|false" - направление сортировки/>

...</Index>

11 / 27

Page 12: Ведение схемы БД в проектах

ТриггерМожно декларировать несколько триггеров на одно и то жесобытие, хотя поддержка на уровне SQL появилась только в 5.7.

<Trigger Определение триггераwhen="before|after" - момент срабатыванияaction="update|insert|delete" - событие срабатывания><SQL>Код триггера</SQL>

</Trigger>

В SQL может понадобиться использовать CDATA.

12 / 27

Page 13: Ведение схемы БД в проектах

Компоновка триггеров: проблема

• MySQL до версии 5.7 не поддерживает несколькотриггеров на одно событие

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

• в стандартных фрагментах возможны конфликтыпеременных

• если в библиотечном триггере ошибка — нужноперегенерировать все триггеры

13 / 27

Page 14: Ведение схемы БД в проектах

Компоновка триггеров: решениеОборачиваем каждый фрагмент в отдельный BEGIN/END - блок:

<Trigger when="before" action="delete"><SQL>...</SQL>

</Trigger><Trigger when="before" action="delete"><SQL>...</SQL>

</Trigger>

CREATE TRIGGER ‘name‘ BEFORE DELETE ON ‘table‘ FOR EACH ROWBEGINBEGIN ... END; // каждый блок — отдельный scopeBEGIN ... END; // для своих переменных

END;

14 / 27

Page 15: Ведение схемы БД в проектах

Внешний ключНе заморачиваемся с именованием CONSTRAINT, простоназываем ключ:

<ForeignKey Определение ForeignKeyname="имя" - имя ключаtable="таблица" - таблица, на которую ссылаемсяdelete="cascade" - поведение при delete (update,update="cascade" - поведение при update cascade,> setnull)<Reference Определение ссылкиlocal="колонка" - ссылающаяся колонкаforeign="колонка" - колонка, на которую ссылаются/>...

</ForeignKey>

15 / 27

Page 16: Ведение схемы БД в проектах

Представление

Явно описываем колонки для документирования.

<View Определение VIEWname="имя" - имя VIEW><ViewColumn Определение колонки VIEW

name="имя" - имя колонки/>

<SQL>SQL-код VIEW</SQL></View>

16 / 27

Page 17: Ведение схемы БД в проектах

Создание схемыСценарий тривиально генерируется из описания, при этом:

• отключаем внешние ключи на время выполнения —избавляемся от проблем с порядком создания таблиц

• перед каждой таблицей добавляем IF NOT EXISTS навсякий случай

• создание индексов и внешних ключей — внутри CREATETABLE

Неудобный момент в синтаксисе MySQL: невозможностьпроверки существования индекса:

CREATE INDEX IF NOT EXISTS

17 / 27

Page 18: Ведение схемы БД в проектах

Модификация схемы

• отключаем внешние ключи на время выполнения —избавляемся от проблем с порядком изменения таблиц

• для колонок, индексов, внешних ключей — ALTER TABLE• синтаксис ALTER TABLE для создания/модификацииэлементов практически совпадает с CREATE TABLE —проще написать преобразование

• триггеры и хранимый код безусловно перегенерируем прикаждом обновлении (пока)

ALTER желательно генерировать автоматически!

18 / 27

Page 19: Ведение схемы БД в проектах

Генерация ALTERАвтоматически если есть cтарое и новое описание:

Для каждой таблицы единый ALTER TABLE:

• удаление индексов, отсутствующих в старой версии• удаление внешних ключей, отсутствующих в старой версии• удаление колонок, отсутствующих в новой версии• создание новых колонок• создание новых индексов• создание новых внешних ключей

Проблема: переименование колонок.

19 / 27

Page 20: Ведение схемы БД в проектах

Расширяемость

Некоторым объектам схемы хотелось бы добавлять некоестандартное поведение:

• таблицы с иерархической структурой данных• денормализованные счетчики для 1→ N• генерация идентификаторов

Как правило, однотипные триггеры, отличающиеся толькоименами колонок и таблиц.

20 / 27

Page 21: Ведение схемы БД в проектах

Использование расширенийРасширяем поведение объектов схемы с помощьюспециальных атрибутов ext:

ext:расширение="значение"ext:расширение.параметр="значение"

<Column name="id" ext:auto="uuid" ... /><Column name="parent" ext:tree="item_tree" ... /><ForeignKey name="category" ext:count="numOfItems" ... >

Каждое расширение реализуется как отдельный XSL.

21 / 27

Page 22: Ведение схемы БД в проектах

Примеры расширений

ext:auto Автоматическая генерация значений поля,например, uuid, rand.Триггеры на добавление записи.

ext:count Автоматические счетчики связанных записей дляотношения 1→ N.Триггеры на добавление, изменение и удалениезаписи.

ext:tree Сlosure table для иерархических данных.Создание таблиц closure, триггеры на добавление,изменение и удаление записи.

22 / 27

Page 23: Ведение схемы БД в проектах

Реализация: baser

• пока тестовый прототип, посмотрим что получится• shell + набор XSL-шаблонов• функциональность в XSL — можно интегрировать в PHP• пока минимальная функциональность• генерация SQL — 500 строк, closure table — 80 строк

23 / 27

Page 24: Ведение схемы БД в проектах

baser: создание схемы

# По умолчанию из database.xml в текущем каталоге:$ baser schema

# Или из указанного файла:$ baser -c db.xml schema

# Можно не всю схему, а отдельную таблицу:$ baser schema mytable

24 / 27

Page 25: Ведение схемы БД в проектах

baser: изменение схемы# Сохраняем текущее состояние:$ baser freeze# Вносим изменения:$ vim database.xml# Генерируем ALTER:$ baser schema# Вносим повторные изменения, если нужно:$ vim database.xml# И так пока не надоест:$ baser schema# Результат нас устраивает,# удаляем сохраненное состояние:$ baser boil

25 / 27

Page 26: Ведение схемы БД в проектах

$ baser graph

category

id bigintparent biginttitle varchar(255)numOfProductsmediumint

BI AI AU BD

parent_title

+ parent+ title

parent_title

product

id bigintcategory bigintnumOfOfferssmallinttitle varchar(255)

BI AI AU AD

category

(id)

(category)

category_title

+ category+ title

category_title

category_offers

+ category+ numOfOffers

category_offers

category_detail

id bigintbody text

category

(id)

(id)

product_detail

id bigintbody text

product

(id)

(id)

offer

id bigintproductbiginttitle varchar(128)price decimal(10,2)

BI AI AU AD

product

(id)

(product)

product_price

+ product+ price

product_price

product_title

+ product+ title

product_title

category_tree

p bigintc bigintd tinyint unsigned

d

+ d

d

26 / 27

Page 27: Ведение схемы БД в проектах

Что дальше

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

• генерация HTML документации по описанию базы• (возможно) визуальный diff

27 / 27