Хранение периодов дат в базе данных
Я хотел бы обсудить "лучший" способ хранения периодов дат в базе данных. Давайте поговорим о SQL/MySQL, но этот вопрос может быть для любой базы данных. У меня ощущение, что я делаю что-то не так годами...
На английском у меня есть информация:
-In year 2014, value is 1000
-In year 2015, value is 2000
-In year 2016, there is no value
-In year 2017 (and go on), value is 3000
Кто-то может хранить как:
BeginDate EndDate Value
2014-01-01 2014-12-31 1000
2015-01-01 2015-12-31 2000
2017-01-01 NULL 3000
Другие могут хранить как:
Date Value
2014-01-01 1000
2015-01-01 2000
2016-01-01 NULL
2017-01-01 3000
- Правила проверки первого метода выглядят как хаос, чтобы развиться, чтобы избежать дыр и наложений.
- Во втором методе проблема состоит в том, чтобы фильтровать одну пунктуальную дату внутри периода.
Что предпочитают мои коллеги? Любое другое предложение?
РЕДАКТИРОВАТЬ: я использовал полный год только, например, мои данные обычно меняются с детализацией дня.
РЕДАКТИРОВАТЬ 2: Я думал об использовании сохраненной "Дата" в качестве "BeginDate", упорядочить строки по дате, а затем выбрать "EndDate" в следующей (или предыдущей) строке. Сохранение "BeginDate" и "Interval" может привести к проблеме дыр / перекрытий в качестве первого метода, которого мне необходимо придерживаться сложного правила проверки.
1 ответ
Это в основном зависит от того, как вы будете использовать эту информацию - я предполагаю, что вы делаете больше, чем просто храните значения в течение года в своей базе данных.
Здесь много догадок, но я думаю, у вас есть другие таблицы с ограниченными во времени данными, и вам нужно сравнить даты, чтобы найти совпадения.
Например, в вашей текущей схеме:
select *
from other_table ot
inner join year_table yt on ot.transaction_date between yt.year_start and yt.year_end
Это должен быть простой запрос для оптимизации - это прямое сравнение данных, и если таблица достаточно большая, вы можете добавить индексы, чтобы ускорить ее.
Во втором предложении схемы это не так просто:
select *
from other_table ot
inner join year_table yt
on ot.transaction_date between yt.year_start
and yt.year_start + INTERVAL 1 YEAR
Важно то, что это сложнее оптимизировать, так как каждое сравнение должно выполнять скалярную функцию. Это может не иметь значения - но с большой таблицей или более сложным запросом это может стать узким местом.
Вы также можете сохранить год как целое число (как рекомендуют некоторые комментаторы).
select *
from other_table ot
inner join year_table yt on year(ot.transaction_date) = yt.year
Опять же - это может оказать влияние на производительность, так как каждое сравнение требует выполнения функции.
Пурист во мне не любит хранить это как целое число - так что вы также можете использовать тип данных MySQL YEAR.
Таким образом, если предположить, что размер данных не является проблемой, для которой вы оптимизируете, решение действительно будет заключаться в том, как ваши данные в этой таблице соотносятся с остальной частью вашей схемы.