Таблицы календаря в PostgreSQL 9
Я создаю базу данных аналитики (у меня есть твердое понимание данных и бизнес-целей и только базовые-умеренные навыки базы данных).
я наткнулся на некоторые ссылки на строительство подобных складов, которые реализуют концепцию "календарных таблиц". Это имеет смысл и достаточно легко сделать. Большинство примеров, которые я вижу, однако, являются таблицами календаря, которые ограничивают область до "дня". Мои данные нужно будет проанализировать до часового уровня. Возможно протокол.
мой вопрос: будет ли реализация таблиц календаря для детализации на уровне часа/минуты иметь значение с точки зрения эффективности пространства и скорости запроса/сортировки? Если да, можете ли вы рекомендовать структуру таблицы и метод/пример заполнения?
моя первичная таблица данных будет содержать 20 + миллионов строк данных в любой момент времени, а типичные подмножества для анализа находятся в диапазоне от 1 до 5 миллионов. Итак, как вы можете видеть, это много полей временных меток.
3 ответов
таблицы календаря реализуют компромисс пространства/времени. Используя больше пространства, некоторые виды запросов выполняются за меньшее время, поскольку они могут использовать индексы. Они безопасны, пока вы осторожны с ограничениями CHECK () и пока у вас есть административные процессы, чтобы позаботиться о любых ограничениях, которые не поддерживает ваша СУБД.
если ваша детализация составляет одну минуту, вам нужно будет генерировать около полумиллиона строк каждый год. Минимальная таблица календаря будет выглядеть вроде этого.
2011-01-01 00:00:00
2011-01-01 00:01:00
2011-01-01 00:02:00
2011-01-01 00:03:00
2011-01-01 00:04:00
если вы делаете анализ "ведра", вам может быть лучше с чем-то вроде этого.
bucket_start bucket_end
--
2011-01-01 00:00:00 2011-01-01 00:01:00
2011-01-01 00:01:00 2011-01-01 00:02:00
2011-01-01 00:02:00 2011-01-01 00:03:00
2011-01-01 00:03:00 2011-01-01 00:04:00
2011-01-01 00:04:00 2011-01-01 00:05:00
поскольку оператор SQL BETWEEN включает конечные точки, вам обычно нужно избегать его использования. Это потому, что он включает конечные точки, и трудно выразить bucket_end как "bucket_start плюс одна минута, минус наименьший бит времени, который может распознать этот сервер". (Опасность-это значение, которое на микросекунду больше, чем bucket_end, но все же меньше, чем следующее значение для bucket_start.)
если бы я собирался построить этот стол, я бы, вероятно, сделал это так. (Хотя я бы подумал, стоит ли называть это "календарем".)
create table calendar (
bucket_start timestamp primary key,
bucket_end timestamp unique,
CHECK (bucket_end = bucket_start + interval '1' minute)
-- You also want a "no gaps" constraint, but I don't think you
-- can do that in a CHECK constraint in PostgreSQL. You might
-- be able to use a trigger that counts the rows, and compares
-- that count to the number of minutes between min(bucket_start)
-- and max(bucket_start). Worst case, you can always run a report
-- that counts the rows and sends you an email.
);
уникальное ограничение создает неявный индекс в PostgreSQL.
этот запрос будет вставлять строки за один день (24 часа * 60 минут) за раз.
insert into calendar
select coalesce(
(select max(bucket_start) from calendar),
cast('2011-01-01 00:00:00' as timestamp)
)
+ cast((n || 'minute') as interval) as bucket_start,
coalesce(
(select max(bucket_start) from calendar),
cast('2011-01-01 00:00:00' as timestamp)
)
+ cast((n + 1 || ' minute') as interval) as bucket_end
from generate_series(1, (24*60) ) n;
вы можете обернуть это в функцию, чтобы генерировать в год. Я бы, вероятно, попытался совершить меньше полумиллиона строк за раз.
это не займет слишком много времени, чтобы создать 20 миллионов строк для тестирования и еще 20 миллионов строк "календарных" минут. Долгий обед. Может быть, полдень на солнце.
на PostgreSQL
, вы можете создать календарь таблицы произвольной длины и детализации на лету:
SELECT CAST('2011-01-01' AS DATE) + (n || ' hour')::INTERVAL
FROM generate_series(0, 23) n
это не требует рекурсии (как и в других системах) и является предпочтительным методом для генерации летучих наборов результатов.
в построенных мной хранилищах данных я использовал отдельные измерения CALENDAR и TIME_OF_DAY. Первое измерение имеет 1-дневную гранулярность, а второе-1-минутную гранулярность.
в двух других случаях я заранее знал, что никакой отчет не потребуется при детализации менее 15 минут. В этом случае для простоты я использовал одно календарное измерение с 96 записями в день.
Я использовал этот подход на складах Oracle до сих пор, но я может быть вовлечен в проект хранилища PostgreSQL этим летом.