2016-08-15 4 views
2

Я хочу построить простую многомерную модель данных, используя схему звезд в реляционной базе данных (ROLAP). Для этого я создаю таблицу фактов и две таблицы измерений. Во-первых, я копирую данные из операционного источника и обрабатываю эти данные (некоторый упрощенный процесс ETL).Что может быть неправильным в этой многомерной модели?

В моей модели только два измерения: date и status. Мера: количество определенных статусов (на время).

время таблица измерения:

CREATE TABLE [dbo].[tbl_date_dim] ( 
    [ID][int]  IDENTITY(1,1) NOT NULL, 
    [date_key][int] NOT NULL primary key, 
    [Year][int]  NOT NULL, 
    [Month][int] NOT NULL, 
    [Day][int]  NOT NULL   
); 

Существует таблица - tbl_application -, в которой хранится весь диапазон времени (поле VersionDate). Таким образом, таблица измерения времени я заполняю этот путь:

INSERT INTO [dbo].[tbl_date_dim] 
    ([date_key], 
    [Year], 
    [Month], 
    [Day]) 
(
    SELECT DISTINCT 
    CAST(YEAR(VersionDate) as VARCHAR(4)) + 
    RIGHT('00' + CAST(MONTH(VersionDate) as VARCHAR(2)) ,2) + 
    RIGHT('00' + CAST(DAY(VersionDate) as VARCHAR(2)), 2) as 'date_key', 
    YEAR(inner_data.VersionDate) as 'Year', 
    MONTH(inner_data.VersionDate) as 'Month', 
    DAY(inner_data.VersionDate)  as 'Day' 
    FROM (
     SELECT 
      VersionDate 
     FROM [dbo].[tbl_application] 
) AS inner_data 
); 

размерность таблицы состояния: Я использую всю существующую таблицу tbl_applicationstatus.

Далее я создаю таблицу фактов. Он содержит внешние ключи к таблицам измерений и мерам.

CREATE TABLE [dbo].[tbl_olap_fact] (
    [ID][int] IDENTITY(1,1) NOT NULL,  

    [status_id][int] NOT NULL,   // FK 
    [date_dim][int] NOT NULL,   // FK 

    [staus_name] varchar(100) NOT NULL, // Non additive measure 
    [transaction_id][int] NOT NULL,  // Additive measure 

    CONSTRAINT [PK_tbl_olap_fact] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY]; 

transaction_id - это поле, которое я агрегировать (число состояний).

Далее я добавляю связь между таблицей фактов и размерами таблицами:

ALTER TABLE [dbo].[tbl_olap_fact] ADD CONSTRAINT [FK_tbl_olap_fact_tbl_date_dim] FOREIGN KEY([date_dim]) 
REFERENCES [dbo].[tbl_date_dim] ([date_key]); 

ALTER TABLE [dbo].[tbl_olap_fact] ADD CONSTRAINT [FK_tbl_olap_fact_tbl_applicationstatus] FOREIGN KEY([status_id]) 
REFERENCES [dbo].[tbl_applicationstatus] ([ID]); 

Затем я заполнить таблицу фактов:

INSERT INTO [dbo].[tbl_olap_fact] 
    ([transaction_id], 
    [status_id], 
    [staus_name], 
    [date_dim]) 
(
    SELECT DISTINCT 
    core.id   as 'transaction_id', 
    core_status.ID as 'status_id', 
    core_status.name as 'status_name', 
    CAST(YEAR(core.VersionDate) as VARCHAR(4)) + 
    RIGHT('00' + CAST(MONTH(core.VersionDate) as VARCHAR(2)) ,2) + 
    RIGHT('00' + CAST(DAY(core.VersionDate) as VARCHAR(2)), 2) as 'date_dim' 
    FROM 
    [dbo].[tbl_application] as core 
     inner join tbl_applicationstatus as core_status 
     on core.ApplicationStatusID = core_status.ID 
    WHERE IsRaw = 0 
); 

В качестве сервера OLAP я использую Мондриан. Mondrian схема, которая определяет логическую модель многомерной базы данных:

<Schema name="olap_schema"> 
    <Dimension type="TimeDimension" visible="true" highCardinality="false" name="Date first dim"> 
    <Hierarchy name="date_hierarchy" visible="true" hasAll="true" primaryKey="date_key" description=""> 

     <Table name="tbl_date_dim" schema="dbo"> 
     </Table> 

     <Level name="" 
      visible="true" 
      table="tbl_date_dim" 
      column="Year" 
      nameColumn="Year" 
      type="Numeric" 
      uniqueMembers="true" 
      levelType="TimeYears" 
      hideMemberIf="Never" 
      description="">   
     </Level> 

     <Level name="" 
      visible="true" 
      table="tbl_date_dim" 
      column="Month" 
      nameColumn="Month" 
      ordinalColumn="Month" 
      type="Numeric" 
      uniqueMembers="false" 
      levelType="TimeMonths" 
      hideMemberIf="Never" 
      description=""> 
     </Level> 

     <Level name="" 
      visible="true" 
      table="tbl_date_dim" 
      column="Day" 
      nameColumn="Day" 
      ordinalColumn="Day" 
      type="Numeric" 
      uniqueMembers="false" 
      levelType="TimeDays" 
      hideMemberIf="Never" 
      description=""> 
     </Level> 

    </Hierarchy> 
    </Dimension> 

    <Dimension type="TimeDimension" visible="true" highCardinality="false" name="Date second dim"> 
    <Hierarchy name="date_hierarchy" visible="true" hasAll="true" primaryKey="date_key" description=""> 
     <Table name="tbl_date_dim" schema="dbo"> 
     </Table> 

     <Level name="" 
      visible="true" 
      table="tbl_date_dim" 
      column="Year" 
      nameColumn="Year" 
      type="Numeric" 
      uniqueMembers="true" 
      levelType="TimeYears" 
      hideMemberIf="Never" 
      description=""> 
     </Level> 

     <Level name="" 
      visible="true" 
      table="tbl_date_dim" 
      column="Month" 
      nameColumn="Month" 
      ordinalColumn="Month" 
      type="Numeric" 
      uniqueMembers="false" 
      levelType="TimeMonths" 
      hideMemberIf="Never" 
      description=""> 
     </Level> 

     <Level name="" 
      visible="true" 
      table="tbl_date_dim" 
      column="Day" 
      nameColumn="Day" 
      ordinalColumn="Day" 
      type="Numeric" 
      uniqueMembers="false" 
      levelType="TimeDays" 
      hideMemberIf="Never" 
      description=""> 
     </Level> 

    </Hierarchy> 
    </Dimension> 

    <Dimension type="StandardDimension" visible="true" highCardinality="false" name="Status dimension"> 
    <Hierarchy name="status_hierarchy" visible="true" hasAll="true" primaryKey="ID" description=""> 
     <Table name="tbl_applicationstatus" schema="dbo"> 
     </Table> 
     <Level name="" 
      visible="true" 
      table="tbl_applicationstatus" 
      column="Name" 
      nameColumn="Name" 
      type="String" 
      uniqueMembers="true" 
      levelType="Regular" 
      hideMemberIf="Never" 
      description=""> 
     </Level> 
    </Hierarchy> 
    </Dimension> 

    <Cube name="enrollment_cube" caption="" visible="true" description="" cache="true" enabled="true"> 
    <Table name="tbl_olap_fact" schema="dbo"> 
    </Table> 

    <DimensionUsage source="Date first dim" name="X axis" caption="" visible="true" foreignKey="date_dim" highCardinality="false"> 
    </DimensionUsage> 

    <DimensionUsage source="Date second dim" name="Y axis" caption="" visible="true" foreignKey="date_dim" highCardinality="false"> 
    </DimensionUsage> 

    <DimensionUsage source="Status dimension" name="Z axis" caption="" visible="true" foreignKey="status_id" highCardinality="false"> 
    </DimensionUsage> 

    <Measure name="TotalCount" column="transaction_id" aggregator="count" caption="Total" visible="true"> 
    </Measure> 

    </Cube> 

</Schema> 

В качестве клиента OLAP я использую Saiku Analytics.

enter image description here

В принципе, я получаю правильные данные - но не совсем уверен в этом. Например, правильно ли это используется для заполнения таблицы фактов? Я строю процесс ETL правильно? Это тестовый режим, и я делаю некоторые эксперименты в создании хранилищ данных и многомерных моделей.

Я был бы очень признателен за информацию. Спасибо всем.

ответ

1

Отказ от ответственности здесь: я никогда не пользовался Мондрианом, и совет, который я приведу здесь, является общим, придерживающимся самого Кимбалла. Если Mondrian требует определенных изменений в схеме, то идите на это.


tbl_date_dim

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

Я бы сделал это, чтобы удалить столбец идентификатора. Какой цели это служит?Каждое значение YYYYMMDD будет уникальным, и стандартный шаблон здесь должен просто использовать это как суррогатный ключ для этой таблицы.

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

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

Я бы предложил заселить tbl_date_dim по-разному. Конечно, то, как вы это делаете, будет работать, но ваше измерение даты в конечном итоге будет упоминаться многими другими таблицами, и вы можете обнаружить, что вам не нужны даты, которые вам нужны. Стандартное решение - это просто написать сценарий или даже скомбинировать таблицу и импортировать ее, а также включить подходящие диапазоны дат в прошлое и будущее. Это никогда не бывает таким большим, поэтому размер не является проблемой. Если вы хотите создать скрипт, вы сможете найти скрипты, которые будут работать для вас с небольшим количеством поиска.

tbl_applicationstatus

Трудно комментировать это, как вы не показывают DDL. Однако вы, возможно, не должны использовать всю исходную таблицу. Удостоверьтесь, что у вас есть суррогатный ключ, созданный в вашем хранилище данных (столбец идентификатора - это хорошо, назовите его что-то вроде application_status_key) и бизнес-ключ. Возможно, это имя status_name.

tbl_olap_fact

Факт стол должен быть один или несколько мер, в то же зерно, и внешние ключи таблицы размерности. Понимание зерна имеет решающее значение, и вы должны думать о том, что такое зерно, а затем дать факт содержательному имени, которое отражает его. Если ваш факт будет иметь одну из других мер, связанных с транзакциями, то tbl_transaction_fact может быть хорошим именем, например.

Непонятно, что вы пытаетесь измерить здесь, так как вы не объясняете, какие данные находятся в исходной таблице tbl_application, но похоже, что вы пытаетесь подсчитать количество транзакций, выполненных в то время как определенный статус приложения был установлен? Обратите внимание, что на самом деле у вас нет каких-либо добавок; добавочная мера - это то, что можно суммировать - денежную сумму, количество предметов и т. д.

Если вы просто делаете это в качестве примера, я настоятельно рекомендую вам сначала подумать о том, что вы хотите, чтобы ваш куб чтобы ответить на что-то, что является добавочным (например, что-то вроде строк «Сколько стоят все приложения, созданные в январе?», если ваши приложения имеют денежное значение), а затем смоделируйте что-то, что позволит ответить на этот вопрос.

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

Вы должны удалить status_name из таблицы фактов, как вы должны это сделать, связавшись с вашим измерением статуса и используя столбцы имен оттуда. Имя статуса - это бизнес-ключ от этого измерения, а не неаддитивная мера.

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


Там в really handy Kimball guide, который дает краткий обзор различных методов. Это действительно удобно, как начальное место для поиска концепций, а также для возврата к тому, когда вам нужно напоминание - я предлагаю дать ему возможность прочитать и сохранить его.

+1

Я дар речи! .. Большое спасибо за такой подробный ответ! Я буду внимательно изучать ... Спасибо, что поделились своим опытом! Это очень важно для меня. –