Любая таблица измерения с богатым набором описательных атрибутов
часто становится непосредственным объектом запросов, независимо
от таблиц фактов. Например, мы ежедневно выполняем различные запросы
к таблице Клиент для ответов на вопросы, сколько у нас клиентов
по типу платежа, региону, полу, тарифному плану. Простой подсчёт
записей в статическом измерении достаточно очевиден, однако наша
жизнь становится значительно интереснее, когда мы пытаемся выполнить
тот же самый подсчёт, но уже в медленно изменяющемся измерении.
Подсчёт элементов медленно изменяющегося измерения
Проблема состоит в том, чтобы не насчитать больше, чем есть. В
таблице медленно изменяющегося измерения "Клиент" у нас
будет несколько записей для каждого клиента, поэтому простой запрос
на подсчёт количества клиентов в определённом регионе возвратит
завышенное количество для всех клиентов, данные о которых изменялись
(и, соответственно, имеется несколько записей). Кто-то, возможно,
склонится к тому, Чтобы выполнить подсчёт путём операции COUNT DISTINCT
над ключами, уникально идентифицирующими клиентов в оперативной
системе, если они доступны. Здесь проблема заключается в том, что
если атрибут, по которому вы проводите подсчёт уникальных значений,
изменился, как в случае изменения статуса клиента, вы всё же рискуете
сделать ошибку, поскольку ключ клиента может быть уникальным в пределах
штата. Нам нужен способ ограничения медленно изменяющегося измерения
до одной записи на каждого клиента. Мы можем это сделать, если наиболее
свежая запись для каждого клиента в таблице измерения будет содержать
признак "текущая запись". Это позволит нам выполнять подсчёт
наиболее актуальных состояний клиентов. Вы даже можете создать отдельную
таблицу, представление или предопределённый запрос, который будет
возвращать записи о клиентах, имеющие только статус "текущая
запись", что позволит их корректно подсчитывать.
Подсчёт за промежутки времени
Подсчёт текущего количества элементов измерения очень полезен,
однако реальную сноровку нужно демонстрировать при подсчёте на определённую
дату из всей истории. Понимание того, как величины изменяются со
временем, является одной из задач хранилища данных. Знание того,
что на данный момент у нас 2311 клиентов полезно, а возможность
сравнить эту величину с количеством клиентов год назад - ещё полезнее.
Чтобы проводить исторические подсчёты подобного рода, вам понадобится
медленно изменяющееся измерение. Например, чтобы подсчитать количество
клиентов на конец 1999 года вы могли бы воспользоваться фильтром
Row_Begin_Date<='12/31/1999' AND Row_End_Date>='12/31/1999'
(выбор операций сравнения зависит от того, как вы установили ваши
даты начала и окончания). В этом примере мы предположили, что когда
в таблице измерения изменяется запись о клиенте, значение поля row_end_date
первой записи на один день меньше значения поля row_begin_date второй
записи, а наличия нескольких изменений в день не допускаются.
Если вы, действительно, хотите проявить воображение, то вместо
прямого ограничения полей таблицы измерения "Клиент",
вы можете использовать всю мощь таблицы измерения "Период"
для предоставления требуемой даты или даже нескольких дат. Используйте
для этого те же самые операции сравнения для того, чтобы создать
два соединения по неравенству с использованием поля Date вашей таблицы
Period и полями Row_Begin_Date и Row_End_Date вашей таблицы измерения
"Клиент". Затем введите ограничение на значение поля Date
таблицы Period, чтобы оно было равно требуемой дате. При этом вы
сможете включить поле Date в результат выборки, чтобы увидеть, к
какой дате относится искомое количество клиентов. Для того чтобы
одним запросом посчитать количество для более, чем одной даты, например
для последнего дня каждого года, уберите ограничение на поле Date
таблицы Period, и добавьте ограничение Month_End_Flag='y'. Оператор
SQL выглядел бы следующим образом:
SELECT Period.Date, Customer.State, COUNT(Customer.Customer_Key)
FROM Customer, Period
WHERE Customer.Row_Begin_Date <=Period.Date
AND Customer.Row_End_Date >=Period.Date
AND Period.Month_End_Flag ='y'
Заметьте, что такой тип соединения по неравенству между таблицей
Period и таблицей измерения может представлять трудности для ядра
СУБД при больших размерах измерений. В нашем случае, мы построили
битовые индексы (bitmapped indexes) по обоим полям с датами и получили
неплохую производительность.
Ясно, что запросы такого рода не так тривиально построить, и мы
бы посоветовали вам оградить ваших пользователей от подобной гимнастики
с запросами. На самом деле, если запросы на подсчёт количества значений
определённых атрибутов является нормальной практикой, может иметь
смысл построение суммарной таблицы фактов, хранящей значение количества
для любой существующей комбинации атрибутов за любой день. Тогда
мы опять возвращаемся к простой многомерной модели, в которой каждый
атрибут является измерением, а таблица фактов имеет, по крайней
мере, одно поле, хранящее значение количества клиентов, сгруппированное
по комбинациям значений атрибутов и по дням.
Если вы нашли в сети интересные ссылки на ресурсы по технологиям
хранилищ данных, OLAP, CRM или data mining, и хотите поделиться
ими с другими, присылайте их.
Я с удовольствием размещу их на этом сайте.