проектная база данных, относящаяся к атрибуту времени - PullRequest
5 голосов
/ 03 ноября 2010

Я хочу создать базу данных, которая описывается следующим образом: Каждый продукт имеет только один статус в один момент времени.Тем не менее, статус продукта может измениться в течение срока его службы.Как я могу спроектировать отношения между продуктом и статусом, которые могут быть запрошены для всего продукта определенного статуса в настоящее время?Кроме того, может ли кто-нибудь дать мне более подробную информацию о базе данных проектирования, которая связана с продолжительностью времени как проблемой выше?Спасибо за любую помощь

Ответы [ 5 ]

7 голосов
/ 07 ноября 2010

Вот модель для удовлетворения ваших заявленных требований.

Ссылка на модель данных временного ряда

Ссылкав нотацию IDEF1X для тех, кто не знаком со стандартом реляционного моделирования.

  • Нормализовано до 5NF;нет повторяющихся столбцов;нет аномалий обновления, нет нулей.

  • Когда статус продукта изменяется, просто вставьте строку в ProductStatus с текущим DateTime.Не нужно трогать предыдущие строки (которые были истинными и остаются верными).Никакие фиктивные значения, которые инструменты интерпретации (кроме вашего приложения) не должны интерпретировать.

  • DateTime - это фактический DateTime, в который Продукт был помещен в этот Статус;«От», если хотите.«До» легко выводится: это DateTime следующей (DateTime> «From») строки для Product;там, где он не существует, значением является текущий DateTime (используйте ISNULL).

Первая модель завершена;(ProductId, DateTime) достаточно для обеспечения уникальности первичного ключа.Однако, поскольку вы запрашиваете скорость для определенных условий запроса, мы можем улучшить модель на физическом уровне и предоставить:

  • Индекс (у нас уже есть индекс PK, поэтому мы улучшим индексво-первых, перед добавлением второго индекса) для поддержки покрытых запросов (те, которые основаны на любом расположении {ProductId | DateTime | Status}, могут быть предоставлены индексом без необходимости перехода к строкам данных).Что изменяет отношение Status :: ProductStatus с Неидентифицирующая (пунктирная линия) на Идентифицирующий тип (сплошная линия).

  • Расположение PK выбирается на основе того, что большинство запросов будет временемСерия, основанная на Product⇢DateTime⇢Status.

  • Второй индекс предназначен для повышения скорости запросов на основе статуса.

  • InАльтернативное Соглашение, которое полностью изменено;т.е. мы в основном хотим текущий статус всех продуктов.

  • Во всех версиях ProductStatus столбец DateTime во вторичном индексе (не PK) имеет значение DESCending;самое последнее - «сначала»Конечно, вам нужно экспериментировать с набором данных разумного размера и принимать собственные решения.Если здесь есть что-то, чего вы не понимаете, пожалуйста, спросите, и я расширю.

    Ответы на комментарии

    Сообщите обо всех продуктах с текущим состоянием 2

    <code>SELECT  ProductId,
            Description
        FROM  Product       p,
              ProductStatus ps
        WHERE p.ProductId = ps.ProductId  -- Join
        AND   StatusCode  = 2             -- Request
        AND   DateTime    = (             -- Current Status on the left ...
            SELECT MAX(DateTime)          -- Current Status row for outer Product
                FROM  ProductStatus ps_inner
                WHERE p.ProductId = ps_inner.ProductId
                )
    • ProductId Индексируется, ведущий столбец, обе стороны

    • DateTime в индексированном, 2 столбец в покрытом запросеОпция

    • StatusCode индексируется, 3-й столбец - в покрытом запросетребуется для удовлетворения внутреннего запроса

    • строки требуются одновременно для одного запроса;они близко друг к другу (благодаря Clstered Index);почти всегда на одной странице из-за короткого размера строки.

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

    Две даты в ProductStatus

    Столбцы, такие как DateTimeFrom и DateTimeTo, являются грубыми ошибками.Давайте рассмотрим это в порядке важности.

    1. Это грубая ошибка нормализации.DateTimeTo легко выводится из единственного DateTime следующей строки;поэтому он является избыточным, дублирующим столбцом.

      • Точность не входит в это: это легко решается с помощью DataType (DATE, DATETIME, SMALLDATETIME).Независимо от того, отображаете ли вы одну секунду, микросекунду или наносекунду, это бизнес-решение;это не имеет ничего общего с данными, которые хранятся.
    2. Реализация столбца DateTo является 100% дубликатом (DateTime следующей строки). Это занимает вдвое больше дискового пространства . Для большого стола это было бы значительным ненужным мусором.

    3. Учитывая, что это короткая строка, вам потребуется вдвое больше логических и физических операций ввода-вывода для чтения таблицы при каждом доступе.

    4. И в два раза больше кэш-памяти (или, иначе, только половина строк будет помещаться в любое данное пространство кеша).

    5. Вводя дубликат столбца, вы ввели возможность ошибки (теперь значение можно получить двумя способами: из дубликата столбца DateTimeTo или DateTimeFrom следующей строки).

    6. Это также Аномалия обновления . При обновлении любого DateTimeFrom обновляется, DateTimeTo предыдущей строки должны быть извлечены (нет ничего сложного, поскольку он близок) и Обновлено (большое дело, поскольку это дополнительный глагол, которого можно избежать).

    7. «Короче» и «ярлыки кодирования» не имеют значения, SQL - это громоздкий язык манипулирования данными, но SQL - это все, что у нас есть (просто справиться с этим). Любой, кто не может кодировать подзапрос, не должен кодировать. Любой, кто дублирует столбец, чтобы облегчить незначительную «сложность» кодирования, не должен моделировать базы данных.

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

    Думайте в терминах наборов

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

    • Для вышеприведенного запроса нам нужен Current DateTime; поскольку ProductStatus представляет собой набор состояний продукта в хронологическом порядке, нам просто требуется последний или MAX (DateTime) set , принадлежащий продукту.

    • Теперь давайте посмотрим на что-то якобы "сложное", с точки зрения наборов . Для отчета о продолжительности пребывания каждого Продукта в определенном состоянии: DateTimeFrom - это доступный столбец, который определяет горизонтальное ограничение: sub set (мы можем исключить более ранние строки); DateTimeTo является самым ранним из подмножества набора состояний продукта.

    <code>SELECT               ProductId,
                         Description,
            [DateFrom] = DateTime,
            [DateTo]   = (
            SELECT MIN(DateTime)                        -- earliest in subset
                FROM  ProductStatus ps_inner
                WHERE p.ProductId = ps_inner.ProductId  -- our Product
                AND   ps_inner.DateTime > ps.DateTime   -- defines subset, cutoff
                )
        FROM  Product       p,
              ProductStatus ps
        WHERE p.ProductId = ps.ProductId 
        AND   StatusCode  = 2             -- Request
    • Мышление в терминах получения следующей строки ориентировано на строки, не - ориентированная на множество обработка. Ухудшается при работе с базой данных, ориентированной на множество. Пусть Оптимизатор сделает все это за вас. Проверьте свой SHOWPLAN, это прекрасно оптимизирует.

    • Неспособность мыслить в наборах , ограничиваясь тем самым написанием только одноуровневых запросов, не является разумным оправданием для: реализации масштабного дублирования и обновления аномалий в базе данных; тратить онлайн ресурсы и дисковое пространство; гарантируя половину производительности. Гораздо дешевле научиться писать простые подзапросы SQL для получения легко получаемых данных.

2 голосов
/ 04 ноября 2010

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

Что ж, существует книга на 400 страниц под названием "Временные данные и«Реляционная модель», которая решает вашу проблему.

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

Во введении к книге также прямо говорится, что «эта книга не о технологии, которая (коммерчески) доступна любому пользователю сегодня».

Все, что я могу заметить, это то, что пользователи хотят использовать временные функции из SQLсистемы, проще говоря, оставляют желать лучшего.

PS

Даже если эти 400 страниц могут быть "сжаты немного", я надеюсь, вы не ожидаете, что я дамРезюме всего значимого содержания в нескольких параграфах здесь на SO ...

1 голос
/ 03 ноября 2010

alt text

1 голос
/ 03 ноября 2010

таблиц, подобных этим:

product
-----------
product_id
status_id
name

status
-----------
status_id
name

product_history
---------------
product_id
status_id
status_time

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

0 голосов
/ 03 ноября 2010

Google "двухвременные базы данных" и "медленно меняющиеся измерения".

Это два названия по сути одного и того же шаблона.

Вам необходимо добавить два столбца отметок времени в таблицу продуктов "VALID_FROM" и "VALID_TO".

Когда статус вашего продукта изменяется, вы добавляете НОВУЮ строку с VALID_FROM of now () некоторыми другими известными эффективными данными / временем и устанавливаете для VALID_TO значение 9999-12-31 23:59:59 или какую-то другую дату смехотворно далеко в будущее. Вам также необходимо записать дату «9999-12-31 ...» в предыдущей текущей строке в текущее время «VALID_FROM» - 1 микросекунда.

Вы можете легко запросить статус продукта в любой момент времени.

...