Временная дизайн базы данных, с поворотом (живые против черновых строк)

StackOverflow https://stackoverflow.com/questions/6318317

Вопрос

Я ищу в реализации объективной версии с дополнительным поворотом необходимости иметь как живые, так и черновые объекты, и могу использовать идеи от кого-то, кто испытывает в этом, так как я начинаю задаваться вопросом, возможно ли это даже без потенциально ужасных хаков.

Я сломаю его на посты с тегами ради примера, но мой вариант использования немного более общий (включает в себя медленно изменяющиеся размеры - http://en.wikipedia.org/wiki/slowly_changing_dimension).

Предположим, у вас таблица сообщений, таблица тегов и таблица Post2tag:

posts (
 id
)

tags (
 id
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id)
)

Мне нужна пара вещей:

  1. Возможность показать, как именно выглядит пост в произвольном времени, в том числе для удаленных строк.
  2. Следите за тем, кто редактирует, что, для полной аудиторской тропы.
  3. Нужен набор материализованных представлений («живые» таблицы) для поддержания ссылочной целостности (то есть ведение ведения регистрации должно быть прозрачностью для разработчиков).
  4. Нужно быть соответствующим образом быстро для жизни а также Последние черновые ряды.
  5. Возможность иметь проект пост сосуществует с живым постом.

Я исследовал различные варианты. До сих пор лучшее, что я придумал (без очков № 4/ #5), похоже на настройку SCD Type6-Hybrid, но вместо того, чтобы иметь текущий логический, существует материализованный вид для текущего ряда. Для всех намерений и целей, это выглядит так:

posts (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by
)

post_revs (
 id,
 rev pkey,
 public,
 created_at,
 created_by,
 deleted_at
)

tags (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by
)


tag_revs (
 id,
 public,
 rev pkey,
 created_at,
 created_by,
 deleted_at
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id),
 public,
 created_at,
 updated_at,
 updated_by
)

post2tag_revs (
 post_id,
 tag_id,
 post_rev fkey post_revs(rev), -- the rev when the relation started
 tag_rev fkey tag_revs(rev), -- the rev when the relation started
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (post_rev, tag_rev)
)

Я использую pg_temporal для поддержания индексов в период (create_at, deleted_at). И я держу различные таблицы в синхронизации с использованием триггеров. Yada Yada Yada ... Я создал триггеры, которые позволяют отменить редактирование на посты/теги таким образом, чтобы проект хранился в Revs без публикации. Это прекрасно работает.

Кроме Когда мне нужно беспокоиться о отношениях, связанных с черновыми строками, на Post2tag. В этом случае весь ад вырвался на свободу, и это намекает на меня, что у меня есть какая -то проблема дизайна. Но у меня заканчиваются идеи ...

Я рассматривал возможность представления дублирования данных (то есть строки Post2TAG, представленные для каждого проекта пересмотра). Этот вид работы, но, как правило, намного медленнее, чем я хотел бы.

Я подумал о внедрении таблиц черновиков для «последнего проекта», но это быстро становится очень уродливым.

Я рассматривал всевозможные флаги ...

Итак, вопрос: существует ли общепринятое средство управления живыми и неживыми рядами в среде, контролируемой строкой? А если нет, то с чем вы пробовали и были достаточно успешными?

Это было полезно?

Решение 4

Думаю, я прибил это. По сути, вы добавляете (уникальное) черновое поле в соответствующие таблицы, и вы работаете над черновиками, как будто они были новым постом/тегом/и т. Д.:

posts (
 id pkey,
 public,
 created_at stamptz,
 updated_at stamptz,
 updated_by int,
 draft int fkey posts (id) unique
)

post_revs (
 id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (id, created_at)
)

tags (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by,
 draft fkey tags (id) unique
)


tag_revs (
 id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (id, created_at)
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id),
 public,
 created_at,
 updated_at,
 updated_by,
 pkey (post_id, tag_id)
)

post2tag_revs (
 post_id,
 tag_id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (post_id, tag_id, created_at)
)

Другие советы

Якорное моделирование это хороший способ реализовать временный DB - см. Википедия статья слишком. Требуется некоторое время, чтобы привыкнуть, но работайте хорошо. Есть Инструмент онлайн -моделирования и если вы загрузите поставляемый файл XML [File -> Load Model from Local File]Вы должны увидеть что -то подобное - также используйте [Layout --> Togle Names].

enter image description here

А [Generate --> SQL Code] будет производить DDL для таблиц, видов и функций времени. Код довольно длинный, поэтому я не публикую его здесь. Проверьте код - вам может потребоваться изменить его для своего БД.

Вот файл для загрузки в инструмент моделирования.

<schema>
<knot mnemonic="EXP" descriptor="Expired" identity="smallint" dataRange="char(1)">
<identity generator="true"/>
<layout x="713.96" y="511.22" fixed="true"/>
</knot>
<anchor mnemonic="US" descriptor="User" identity="int">
<identity generator="true"/>
<attribute mnemonic="USN" descriptor="UserName" dataRange="varchar(32)">
<layout x="923.38" y="206.54" fixed="true"/>
</attribute>
<layout x="891.00" y="242.00" fixed="true"/>
</anchor>
<anchor mnemonic="PO" descriptor="Post" identity="int">
<identity generator="true"/>
<attribute mnemonic="TIT" descriptor="Title" dataRange="varchar(2)">
<layout x="828.00" y="562.00" fixed="true"/>
</attribute>
<layout x="855.00" y="471.00" fixed="true"/>
</anchor>
<anchor mnemonic="TG" descriptor="Tag" identity="int">
<identity generator="true"/>
<attribute mnemonic="TGT" descriptor="TagText" dataRange="varchar(32)">
<layout x="551.26" y="331.69" fixed="true"/>
</attribute>
<layout x="637.29" y="263.43" fixed="true"/>
</anchor>
<anchor mnemonic="BO" descriptor="Body" identity="int">
<identity generator="true"/>
<attribute mnemonic="BOT" descriptor="BodyText" dataRange="varchar(max)">
<layout x="1161.00" y="491.00" fixed="true"/>
</attribute>
<layout x="1052.00" y="465.00" fixed="true"/>
</anchor>
<tie timeRange="datetime">
<anchorRole role="IsTagged" type="PO" identifier="true"/>
<anchorRole role="IsAttached" type="TG" identifier="true"/>
<anchorRole role="BYAuthor" type="US" identifier="false"/>
<knotRole role="Until" type="EXP" identifier="false"/>
<layout x="722.00" y="397.00" fixed="true"/>
</tie>
<tie timeRange="datetime">
<anchorRole role="Contains" type="PO" identifier="true"/>
<anchorRole role="ContainedIn" type="BO" identifier="false"/>
<layout x="975.00" y="576.00" fixed="true"/>
</tie>
<tie>
<anchorRole role="CreatedBy" type="TG" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="755.10" y="195.17" fixed="true"/>
</tie>
<tie>
<anchorRole role="CreatedBy" type="PO" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="890.69" y="369.09" fixed="true"/>
</tie>
<tie>
<anchorRole role="ModifiedBy" type="BO" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="1061.81" y="322.34" fixed="true"/>
</tie>
</schema>

Я внедрил временную базу данных, используя правила и триггеры PostgreSQL, и завершил ее в автономный пакет для Activerecord: http://github.com/ifad/chronomodel

Однако дизайн не зависит от языка / структуры - вы можете создавать правила и триггеры вручную, а база данных позаботится об остальном. Посмотри на https://github.com/ifad/chronomodel/blob/master/readme.sql.

Также эффективная индексация и запрос временных данных с использованием геометрических операторов включены в качестве бонуса. :-)

У Post2tag_REVS есть проблема в том, что он пытается выразить 2 принципиально разные понятия.

Тэг, применяемый к револютному пересмотру Post, только когда -либо применяется к этой пересмотре, если не публикуется пересмотр.

Как только тег опубликован (т.е. связан с опубликованной ревизией Post), он применяется к каждому будущему пересмотру поста, пока он не будет отменен.

И связать с опубликованным пересмотром, или неасоцированием, не обязательно одновременно с публикацией пересмотра, если только вы искусственно исполняете это, клонируя пересмотр, чтобы вы могли связать дополнения или удаления тегов ...

Я бы изменил модель, сделав Post2tag_Revs.post_rev, актуальным только для черновых тегов. После того, как ревизия опубликована (и тег живой), я бы использовал столбец штампа времени, чтобы отметить начало и конец опубликованной достоверности. Вы можете или не можете хотеть новую запись после 2TAG_REVS представлять это изменение.

Как вы указываете, это делает эти отношения би-временный. Анкет Вы можете повысить производительность в «нормальном» случае, добавив логический в Post2tag, чтобы указать, что тег в настоящее время связан с постом.

Используйте только 3 таблицы: сообщения, теги и пост2TAG.

Добавьте столбцы start_time и end_time во все таблицы. Добавьте уникальный индекс для ключа, start_time и end_time. Добавьте уникальный индекс для ключа, где end_time - NULL. Добавить тригеры.

Для текущего:

SELECT ... WHERE end_time IS NULL

Вовремя:

WHERE (SELECT CASE WHEN end_time IS NULL
THEN (start_time <= at_time)
ELSE (start_time <= at_time AND end_time > at_time)
END)

Поиск текущих данных не является медленным из -за функционального индекса.

Редактировать:

CREATE UNIQUE INDEX ... ON post2tag (post_id, tag_id) WHERE end_time IS NULL;
CREATE UNIQUE INDEX ... ON post2tag (post_id, tag_id, start_time, end_time);

FOREIGN KEY (post_id, start_time, end_time) REFERENCES posts (post_id, start_time, end_time) ON DELETE CASCADE ON UPDATE CASCADE;
FOREIGN KEY (tag_id, start_time, end_time) REFERENCES tags (tag_id, start_time, end_time) ON DELETE CASCADE ON UPDATE CASCADE;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top