Я строй базы данных Postgres , где будет много группирования вещей по month
и year
, но никогда за date
.
- Я мог бы создать целое число
month
иyear
столбцы и использовать их. - Или я мог бы иметь
month_year
столбец и всегда устанавливать вday
1.
Первый выглядит немного проще и понятнее, если кто-то смотрит на данные, но последний приятен тем, что использует правильный тип.
postgresql
database-design
datetime
Дэвид Н. Уэлтон
источник
источник
month
который содержит два целых числа. Но я думаю, что если вам никогда не понадобится день месяца, возможно, проще использовать два целых числаОтветы:
Лично, если это дата или может быть дата, я предлагаю всегда хранить ее как единое целое. С этим просто легче работать, как правило.
У вас может быть одна дата, которая будет поддерживать день, если она вам когда-либо понадобится, или одна
smallint
для года и месяца, которая никогда не будет поддерживать дополнительную точность.Образец данных
Давайте посмотрим на пример сейчас. Давайте создадим 1 миллион дат для нашего образца. Это примерно 5000 строк за 200 лет между 1901 и 2100 годами. Каждый год должно быть что-то на каждый месяц.
тестирование
просто
WHERE
Теперь мы можем проверить эти теории неиспользования даты. Я запускал каждую из них несколько раз, чтобы согреться.
Теперь давайте попробуем другой метод с ними отдельно
Справедливости ради, они не все 0,749 .. некоторые немного более или менее, но это не имеет значения. Они все относительно одинаковы. Это просто не нужно.
В течение одного месяца
Теперь давайте повеселимся. Допустим, вы хотите найти все интервалы в течение 1 месяца с января 2014 года (того же месяца, который мы использовали выше).
Сравните это с комбинированным методом
Это и медленнее, и страшнее.
GROUP BY
/ORDER BY
Комбинированный метод,
И снова с композитным методом
Вывод
В общем, пусть умные люди делают тяжелую работу. Свидания трудны, мои клиенты не платят мне достаточно. Я имел обыкновение делать эти тесты. Мне было трудно когда-либо прийти к выводу, что я могу получить лучшие результаты, чем
date
. Я перестал пытатьсяОБНОВЛЕНИЕ
@a_horse_with_no_name предлагается для моего теста в течение одного месяца
WHERE (year, month) between (2013, 12) and (2014,2)
. На мой взгляд, хотя это круто, это более сложный запрос, и я бы предпочел его избегать, если бы не было выигрыша. Увы, это было все еще медленнее, хотя это близко - что является большим количеством взятия от этого теста. Это просто не имеет большого значения.источник
date
это путь в большинстве случаев.В качестве альтернативы предложенному Эвану Кэрроллу методу, который я считаю, вероятно, лучшим вариантом, я использовал в некоторых случаях (и не особенно при использовании PostgreSQL) только
year_month
столбец типаINTEGER
(4 байта), вычисляемый какТо есть вы кодируете месяц двумя правыми десятичными цифрами (цифра 0 и цифра 1) целого числа, а год - цифрами от 2 до 5 (или более, если необходимо).
Это, в некоторой степени, альтернатива бедняку для создания вашего собственного
year_month
типа и операторов. У него есть некоторые преимущества, в основном «ясность намерений» и некоторая экономия места (я думаю, не в PostgreSQL), а также некоторые неудобства по сравнению с наличием двух отдельных столбцов.Вы можете гарантировать, что значения действительны, просто добавив
Вы можете иметь
WHERE
пункт, похожий на:и это работает эффективно (если
year_month
столбец, конечно, правильно проиндексирован).Вы можете группировать по
year_month
тому же принципу, что и по дате, и с той же эффективностью (по крайней мере).Если вам нужно разделить
year
иmonth
, вычисление является простым:Что неудобно : если вы хотите добавить 15 месяцев к
year_month
вычислению, вы должны вычислить (если я не сделал ошибку или упущение):Если вы не будете осторожны, это может привести к ошибкам.
Если вы хотите узнать количество месяцев между двумя year_months, вам нужно сделать несколько похожих вычислений. Это (с большим количеством упрощений) то, что действительно происходит в тайне с арифметикой дат, к счастью, скрыто от нас через уже определенные функции и операторы.
Если вам нужно много этих операций, использование
year_month
не слишком практично. Если вы этого не сделаете, это очень четкий способ прояснить ваши намерения.В качестве альтернативы вы можете определить
year_month
тип, определить операторyear_month
+interval
, а также другойyear_month
-year_month
... и скрыть вычисления. Я на самом деле никогда не использовал так много, чтобы чувствовать необходимость на практике. Аdate
-date
на самом деле скрывает что-то подобное.источник
Как альтернатива методу Жоаноло =) (извините, я был занят, но хотел написать это)
БИТ РАДОСТЬ
Мы собираемся сделать то же самое, но с кусочками. Один
int4
в PostgreSQL является целым числом со знаком, в диапазоне от -2147483648 до +2147483647Вот краткий обзор нашей структуры.
Запоминание месяца.
pow(2,4)
это 4 бита .Вот наша битовая карта, где хранятся месяцы.
Месяцы, 1 января - 12 декабря
Годы. Оставшиеся 28 бит позволяют нам хранить информацию о годе
На данный момент нам нужно решить, как мы хотим это сделать. Для наших целей мы могли бы использовать статическое смещение, если нам нужно покрыть только 5000 г. н.э., мы могли бы вернуться к тому,
268,430,455 BC
что в значительной степени охватывает весь мезозой и все полезное, двигаясь вперед.И теперь у нас есть зачатки нашего типа, срок действия которых истекает через 2700 лет.
Итак, давайте приступим к созданию некоторых функций.
Быстрый тест показывает, что это работает ..
Теперь у нас есть функции, которые мы можем использовать в наших двоичных типах.
Мы могли бы вырезать еще один бит из подписанной части, сохранить год как положительный, а затем, естественно, отсортировать его как подписанный int. Если бы скорость была более высоким приоритетом, чем пространство для хранения, это был бы путь, по которому мы шли. Но пока у нас есть свидание, которое работает с мезозой.
Я могу обновить это позже, просто для удовольствия.
источник