2017-01-07 7 views
1

Я бизнес-аналитик и подготовил таблицы/erd для системы, которую мы реализуем.Должен ли я использовать дату вступления в силу, дату начала и дату окончания для исторической записи?

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

В моей рекомендации и в оригинальном дизайне таблиц было поле под названием «Дата вступления в силу», поэтому по существу эффективно с даты и далее действительное действие «Действие».

Скажем, например, Джон присоединился к организации в качестве консультанта 1 января 2017 года, таким образом, он был нанят, поэтому дата вступления в силу 1 января 2017 года и он был консультантом в течение определенного периода времени, пока не стал старшим консультантом 6-го сентября 2017 года, таким образом, дата вступления в силу - 6 сентября 2017 года с акцией, выдвинутой для этой записи.

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

Теперь мой босс и тому Архитектор решений не рекомендовал использовать «Дату вступления в силу», мой босс говорит, что будут «проблемы» с расчетом, но не уточняется, и Архитектор решений говорит, что было бы проще использовать дату начала и дату окончания вместо даты вступления в силу. Его обоснование заключается в том, что нет даты окончания действия действия/события, но неактивна после предоставления конечной даты.

Моя проблема заключается в том, что нам придется поддерживать дополнительную колонку, которая, как я чувствую, абсолютно не нужна.

Что думает о мозге StackOverflow?

Спасибо :)

+0

Любая возможность использовать временную таблицу (https://msdn.microsoft.com/en-us/library/mt631669.aspx)? –

+0

Этот вопрос, вероятно, лучше задать на [dba.se] (http://dba.stackexchange.com/). –

+0

Спасибо всем за ваши ответы! – JackSparrow123

ответ

3

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

Все более StackOverflow вы найдете вопросы о написании запросов, чтобы найти конечную дату данной записи, когда он определен на «следующий» записи, а не «текущий» запись Эти запросы некрасиво и медленно

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

Что касается комментариев ваших коллег о недействительной дате вступления в силу: вы не предоставляете много информации, поэтому я угадаю. Я предполагаю, что есть настоящая «эффективная дата», когда дело произошло, но есть еще один набор дат начала и окончания, которые являются датами расчета заработной платы, к которым относится изменение. Поэтому, если кто-то начнет 1-й, дата вступления в силу платежной ведомости может быть фактически 15-й. Это также может быть использовано для расчетов FTE. Заработная плата и периоды оплаты действительно очень сложны и довольно сложны, поэтому вам не следует недооценивать сложность. Если вы включаете расчеты оплаты в этой системе, то, по крайней мере, вам нужно понять, какие эффективные даты начисления заработной платы.

Вы не должны бояться хранить четыре столбца даты вместо одного. Базы данных там, чтобы сделать вещи легко для вас не сложнее.

+0

Большое вам спасибо! :) Я предполагаю, что одна из причин, почему я предпочитаю «Эффективную дату», - это то, что использует PeopleSoft в своем бэкэнд. Но ваш ответ прекрасен, я пойду с комбинацией даты начала и окончания. – JackSparrow123

+0

Все они являются действительными именами, если они являются непротиворечивыми. Как EffectiveStartDate, EffectiveEndDate, PayrollStartDate, PayrollEndDate. –

3

Ваши инстинкты служат вам хорошо. Не используйте дату окончания. Это добавляет усложнение и источник возможных аномальных данных. Возьмите следующие последовательные записи:

ID <attr> StartDate EndDate 
1 ... Jan 1  Jan 20 
1 ... Jan 20 Jan 22 
1 ... Feb 1  Jul 30 

Там было изменение состояния записано на 1 января, который был в силе до следующего изменения состояния на 20 января Теперь у нас есть проблемы. Согласно EndDate этой версии, 22 января произошло другое изменение состояния, но следующая версия началась 1 февраля.

Это создает пробел в потоке времени, и мы не имеем указаний, где лежит проблема. Является ли EndDate от 22 января неправильным? Является ли StartDate 1 февраля неправильным? Или есть недостающая версия, которая соединяет два конца разрыва? Невозможно сказать.

ID <attr> StartDate EndDate 
1 ... Jan 1  Jan 20 
1 ... Jan 20 Feb 20 
1 ... Feb 1  Jul 30 

Теперь существует перекрытие состояний. Второе государство якобы продолжалось до 20 февраля, но третье государство заявляет, что оно началось 1 февраля. Но начало одного состояния логически означает конец предыдущего состояния. Опять же, мы понятия не имеем (просто посмотрев на данные), дата которых неверна.

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

ID <attr> EffDate 
1 ... Jan 1 
1 ... Jan 20 
1 ... Feb 1 

Теперь пробелы и перекрытия невозможны. Каждое состояние начинается с даты вступления в силу и заканчивается, когда начинается следующее состояние. Поскольку поле EffDate является частью PK, никакая запись не может иметь одинаковое значение EffDate для заданного значения ID.

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

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

create table Employees(
    ID  int auto_generated primary key, 
    Hired  date not null, 
    FName  varchar not null, 
    LName  varchar not null, 
    Sex  enum -- M or F 
    BDay  date, 
    Position enum not null, 
    PayRate currency, 
    DeptID int references Depts(ID) 
); 

Если мы хотим отслеживать изменения данных, мы можем добавить эффективное поле даты. Однако учтите, что данные, такие как дата найма и дата рождения, не будут изменяться с одной версии на другую. Таким образом, они зависят только от поля ID. Данные, которые меняются (Position, PayRate, DeptID), зависят от идентификатора и. Таблица больше не находится в 2nf.

Так нормировать:

create table Employees(
    ID  int auto_generated primary key, 
    Hired  date not null, 
    FName  varchar not null, 
    Sex  enum -- M or F 
    BDay  date 
); 

create table Employees_V(
    ID  int not null references Employees(ID), 
    EffDate date not null, 
    LName  varchar not null, 
    Position enum not null, 
    PayRate currency, 
    DeptID int references Depts(ID), 
    constraint PK_Employees_V primary key(ID, EffDate) 
); 

Фамилию можно ожидать изменения в настоящее время, а затем, особенно среди женщин, работающих.

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

Запрос для получения «текущего» данные относительно прост:

select e.ID, e.Hired, e.FName, v.Lname, e.Sex, e.BDay, v.Position, v.PayRate, v.DeptID 
from Employees e 
join Employees)V v 
    on v.ID = e.ID 
    and v.EffDate =(
    select Max(EffDate) 
    from Employees_V 
    where ID = v.ID 
     and EffDate <= GetDate()) 
where e.ID = 123; 

Сравните запрашивая таблицу с начала/даты окончания.

select ID, Hired, FName, Lname, Sex, BDay, Position, PayRate, DeptID 
from Employees 
where ID = 123 
    and StartDate >= GetDate() 
    and EndDate < GetDate(); 

Предполагается, что значение EndDate для текущей версии является магическим значением, таким как 12/31/9999.

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

Я использовал эту технику около 8 лет, и мне никогда не приходилось ее менять из-за проблем с производительностью. Запрос vnf выполняется в в худшем случае менее чем на 10% медленнее, чем начальная/конечная версия. Таким образом, один минутный запрос займет около одной минуты 5 секунд. Однако при некоторых условиях запрос vnf будет выполняться быстрее.

Возьмите объекты, которые имеют много и много изменений (много тысяч версий). Запрос start/end выполняет сканирование индекса. Он начинается с самой ранней версии и должен проверять каждую версию последовательно, пока не найдет тот, у которого значение EndDate меньше заданной даты. Обычно это последняя версия. В запросе vnf подзапрос позволяет выполнять поиск индекса.

Так что не отвергайте этот дизайн, потому что считаете его медленным. Это не медленно. Особенно, если учесть, что для вставки новой версии требуется только одна инструкция INSERT. При работе с датами начала и окончания вставка новой версии требует UPDATE, а затем INSERT. Это два UPDATE и INSERT при вставке новой версии между двумя существующими версиями. Для удаления начальной/конечной версии требуется одно или два оператора UPDATE и один DELETE. Чтобы удалить версию vnf, просто удалите версию.

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

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

+0

Благодарим вас за обширную информацию, это отличная подробная информация, которая мне полезна. Я дам разработчикам знать, но в конечном итоге им решать, что делать. – JackSparrow123

+0

С уважением не согласен, я думаю, что здесь есть две проблемы с логикой: 1) Забота о пробелах и перекрывающихся датах должна управляться логикой в ​​программах, вставляющих данные в эти таблицы - если эти условия не логически возможны, эти программы не должны допускать их. 2) Я не уверен, что удаление конечных дат устраняет проблему пробелов. Во всяком случае, он просто скрывает их - в данных могут возникать пробелы, но они не будут замечены в базе данных. На самом деле, я не уверен, что этот подход дает вам способ моделирования пробелов, если вы хотите их. – Ben

+0

1) Могу только сказать, удачи! Очень много времени на разработку, тестирование и процессорное время тратится каждый день, пытаясь разработать код, который обеспечит только жизнеспособные данные, которые попадают в базу данных. Только усилия по техническому обслуживанию могут быть довольно грозными. Затем разработчик db запускает скрипт, вносящий изменения, которые обходят весь этот код. Первый закон хорошего проектирования данных: обеспечить целостность данных в максимально возможном месте. Код приложения - это самое высокое место. 2) Да, если пробелы и/или перекрытия допустимы или желательны, этот проект не будет работать. Но для моделирования непрерывной цепочки изменений состояния, я думаю, что нет ничего лучше. – TommCatt

Смежные вопросы