Во-первых, я не вижу проблем в описании их как таблиц измерений и фактов за пределами склада:)
С точки зрения концептуализации и понимания отношений, я лично считаю, что использование дат начала / окончания очень легко для понимания людьми. Разрешение таблиц фактов агента и местоположения, а затем таблиц отображения, зависящих от времени, таких как Agent_At_Location и т. Д. Однако у них есть проблемы, достойные внимания.
Если EndDate равен 2008-08-30
, был ли сотрудник в этом месте ДО 30 августа или ДО и ВКЛЮЧЕНО 30 августа.
Работа с перекрывающимися периодами дат в запросах может привести к запутанным запросам, но, что более важно, к медленным запросам.
Первый кажется просто условным, но он может иметь определенные последствия при работе с другими данными. Например, предположим, что конечная дата 2008-08-30
означает, что они находятся в этом месте ДО и ВКЛЮЧЕНО 30 августа. Затем вы присоединяетесь к их ежедневным агентским данным за этот день (например, когда они действительно прибыли на работу, уехали на перерывы и т. Д.). Вам необходимо присоединиться к ON AgentDailyData.EventTimeStamp < '2008-08-30' + 1
, чтобы включить все события, которые произошли в этот день.
Это потому, что EventTimeStamp данных измеряется не в днях, а, вероятно, в минутах или секундах.
Если вы считаете, что Конечная дата '2008-08-30' означает, что Агент находился в этом местоположении ДО, но НЕ ВКЛЮЧИЛ 30 августа, объединению не требуется + 1
. На самом деле вам не нужно знать, связана ли дата с ДНЕМ, или может включать компонент времени или нет. Вам просто нужно TimeStamp < EndDate
.
С помощью ЭКСКЛЮЗИВНЫХ маркеров конца все ваши запросы упрощаются и никогда не требуют + 1 day
или + 1 hour
для обработки краевых условий.
Второй гораздо сложнее решить. Простейший способ разрешения перекрывающегося периода заключается в следующем:
SELECT
CASE WHEN TableA.InclusiveFrom > TableB.InclusiveFrom THEN TableA.InclusiveFrom ELSE TableB.InclusiveFrom END AS [NetInclusiveFrom],
CASE WHEN TableA.ExclusiveFrom < TableB.ExclusiveFrom THEN TableA.ExclusiveFrom ELSE TableB.ExclusiveFrom END AS [NetExclusiveFrom],
FROM
TableA
INNER JOIN
TableB
ON TableA.InclusiveFrom < TableB.ExclusiveFrom
AND TableA.ExclusiveFrom > TableB.InclusiveFrom
-- Where InclusiveFrom is the StartDate
-- And ExclusiveFrom is the EndDate, up to but NOT including that date
Проблема с этим запросом заключается в индексации. Первое условие TableA.InclusiveFrom < TableB.ExclusiveFrom
может быть разрешено с помощью индекса. Но это может дать Массивный диапазон дат. И затем, для каждой из этих записей, ExclusiveDate
могут быть примерно чем угодно, и, конечно, не в том порядке, который мог бы помочь быстро разрешить TableA.ExclusiveFrom > TableB.InclusiveFrom
Решение, которое я ранее использовал для этого, состоит в том, чтобы иметь максимально допустимый разрыв между InclusiveFrom
и ExclusiveFrom
. Это позволяет что-то вроде ...
ON TableA.InclusiveFrom < TableB.ExclusiveFrom
AND TableA.InclusiveFrom >= TableB.InclusiveFrom - 30
AND TableA.ExclusiveFrom > TableB.InclusiveFrom
Условие TableA.ExclusiveFrom > TableB.InclusiveFrom
STILL не может использовать индексы. Но вместо этого мы ограничили количество строк, которые могут быть возвращены с помощью поиска TableA.InclusiveFrom
. Данные не более чем за 30 дней, потому что мы знаем, что мы ограничили продолжительность максимум 30 днями.
Примером этого является разбивка ассоциаций по календарному месяцу (максимальная продолжительность 31 день).
EmployeeId | LocationId | EffectiveDate | EndDate
1 | 2 | 2007-04-01 | 2008-05-01
1 | 2 | 2007-05-01 | 2008-06-01
1 | 2 | 2007-06-01 | 2008-06-25
(Representing Employee 1 being in Location 2 from 1st April to (but not including) 25th June.)
Это фактически компромисс; использование дискового пространства для увеличения производительности.
Я даже видел, как это приводит к тому, что на самом деле не хранятся диапазоны дат, а хранится фактическое отображение для каждого дня. По сути, это похоже на ограничение максимальной продолжительности до 1 дня ...
EmployeeId | LocationId | EffectiveDate
1 | 2 | 2007-06-23
1 | 2 | 2007-06-24
1 | 3 | 2007-06-25
1 | 3 | 2007-06-26
Инстинктивно я изначально восстал против этого. Но в последующих ETL, Warehousing, Reporting и т. Д. Я действительно нашел его очень мощным, адаптируемым и обслуживаемым. Я на самом деле видел, как люди делают меньше ошибок в коде, пишут код за меньшее время, код в конечном итоге работает быстрее и гораздо лучше адаптируется к меняющимся потребностям клиентов.
Только две нижние стороны были:
1. Занято больше дискового пространства (но по сравнению с таблицами фактов меньше)
2. Вставки и обновления для этого сопоставления были медленнее
Фактическое замедление для вставок и обновлений имеет значение только один раз, когда эта модель использовалась для представления постоянно меняющейся сети процессов; где приложение хотело изменить отображение примерно 30 раз в секунду. Даже тогда это сработало, но затрачивало больше процессорного времени, чем было идеально.