Аруп Нанда
член-директор Oracle ACE

 

Хранилища данных и OLAP
(Data Warehousing and OLAP, by Arup Nanda )

Источник: otn.oracle.com, серия публикаций по технологиям Oracle, серия Oracle Database 11g: The Top New Features for DBAs and Developers ( "Новые возможности для администраторов БД и разработчиков Oracle Database 11g), статья 19, http://www.oracle.com/technology/pub/articles/oracle-database-11g-top-features/11g-dw-olap.html

В этой статье:

  • хранимые в базе данных (database-resident) материализованные представления, организованные как кубы (Cube Organized Materialized Views), которые сочетают функциональность OLAP-кубов с простотой SQL и не требуют при этом использования специальных средств;
  • более легкая идентификация обновлений (refresh) с отслеживанием изменений разделов (partition change tracking);
  • новый Analytic Workspace Manager;
  • механизм Query Rewrite, расширенный до подзапросов (subqueries) и удаленных таблиц;
  • и многие другие новые функции делают Oracle Database еще более привлекательной платформой для создания хранилищ данных и работы с ними.

Материализованные представления, организованные как кубы.

В середине 1990-х годов предложенная Т. Коддом в 1992 концепция Online Analytic Processing (OLAP), то есть оперативная аналитическая обработка данных, которая собственно известна с 1970-х, стала общепризнанной вместе с термином "OLAP". Будучи тогда в какой-то степени эзотеричной (esoteric - понятный лишь немногим), OLAP была концепций, которую большинство видов бизнеса не знало, как правильно использовать в то время. Спустя годы эта технология была значительно улучшена, что сделало возможным применение OLAP с большими хранилищами данных, тем самым действительно принося "intelligence" («интеллектуальность») в аналитику данных (business intelligence). Значительно отличаясь от традиционных реляционных схем, OLAP предоставляет наиболее эффективные возможности хранения данных и доступа к ним, что позволяет конечным пользователям пересекать края (traverse the edges) гипотетического многомерного "куба". (Смотрите ниже пример такого куба).

Размерности (dimensions) куба ассоциируются с фактами (также называемыми измерениями "measures"). Согласно реляционной терминологии у фактов имеют место отношения “многие к одному" с размерностями. Например, компания Acme Computer Supplies имеет базу данных для продавцов. Ее размерности, как правило, - Customers (клиенты), Products (продукты) и Time Element (период - month, quarter, etc.). Сумма продаж некоторого продукта (Cat5e cables) некоторому клиенту (Oracle Corp.) за некоторый период времени (Aug 2008) – это один факт (measure). Размерности хранятся в отдельных таблицах, также хранятся и факты – в данном случае сумма продаж. Так что, используя реляционную терминологию, таблица фактов (с данной суммой продаж) – это порожденная (child) таблица для таблиц размерностей.

Но здесь аналогии заканчиваются. Доступ к измерениям measures в реляционной схеме осуществлялся бы через индексы, созданные на столбцах customer, product или time таблицы fact. При использовании OLAP-подхода доступ к специфицированным клеткам (cell – ячейка) – измерениям осуществляется благодаря пересечению этого куба: в этом примере благодаря переходу к слою, содержащему заданный период - Aug 08; затем продукт - Cat5e; и, наконец, клиент - Oracle. Oracle знает как добраться до этих слоев, благодаря вычислениям цели в массиве (куба), не в таблице. К примеру, предположим, что размерности организованы, как показано ниже:

Dimension Time := {'May','Jun','Jul','Aug'}
Dimension Customer := {'Microsoft','IBM','Oracle','HP'}
Dimension Product := {'Fiber','Cat6e','Cat5e','Serial'}

Чтобы обнаружить факт для Oracle + Aug + Cat5e, OLAP-движок выполняет навигацию примерно такого типа:

  1. Aug 08 - это четвертый элемент массива, называемого Time, так что переходим по измерению time данного куба к четвертой клетке
  2. Cat5e – это третий элемент массива Product, так что переходим к этому третьему элементу
  3. Oracle - это третий элемент массива Customer, поэтому переходим к этому элементу

Вот так вы добрались до того измерения, которое вам нужно. Это сделано без индексов, так как значения размерностей служат как указатели массива. Аналогично, если вы хотите вычислить общие суммы продаж по всем клиентам в Aug 08, вы сделаете то же самое, что проделано выше, за тем исключением, что на шаге Step 3 вы просуммируете все факты элементов массива без перехода к специфицированной клетке.

Контраст между таким подходом и реляционным доступом в чисто реляционной форме данных, хранимых в классической схема звезда, показан ниже.

В подходе с применением реляционной базы данных вы должны соединить (join) эту "fact" таблицу со всеми размерностями. Каждый раз, когда нужны данные, нужно их выбрать (select) из этой fact таблицы, возможно через индексы, и соединить их с каждой размерностью одна за другой, опять-таки через индексы. Хотя технически вполне это возможно, такой подход все-таки нереален с большими базами данных.

В качестве альтернативы, что можно сказать о создании материализованных представлений – MV (Materialized Views) для всех этих выборок? Пользователь мог бы использовать любые комбинации элементов в размерностях:

  • Продажи Cat5e в Aug всем клиентам
  • Продажи в Oracle продукта Serial Cable в Aug, как процент продаж в IBM того же самого продукта и за тот же период
  • Продажи продукта Fiber Cables в HP, как процент продаж продукта Serial Cables в Microsoft и т.д.

Но как много MV нужно создать? Теоретически, одно для каждой комбинации (4 x 4 x 4 = 64 MV). Помимо пространства, имеет место нужда во времени и ресурсах базы данных для освежения MVs, когда их данные изменятся, и во все это вовлечены тысячи элементов. Следовательно, число создаваемых и управляемых MV становится огромным.

По контрасту с этим, куб (cube) – это единый сегмент, который одинаково легко справляется с любыми типами запросов. Хотя оба они (MV и куб – прим. пер.) используются при проектировании хранилищ данных для более быстрой обработки суммарных, а не для (детальных) данных OLTP, тем не менее между ними есть фундаментальная разница: в то время как MV хранят предварительно вычисленные (pre-computed) результаты, чтобы избежать соединений (joins) и других операций агрегирования, кубы хранят сырые/исходные данные и вычисляют большинство сумм на лету. (Ударение на слове "most" (большинство), так как некоторые суммы уже созданы. Куб решает, какие агрегирования/суммы полезны, и создает только их. Во всех остальных случаях суммы вычисляются на лету.) Так как пути доступа через массивы (кубов) основаны на вычислениях, то выборка данных в кубах происходит значительно быстрее, чем в реляционных таблицах типа MV. OLAP-объекты, такие как кубы, хранятся в специальных областях базы данных, называемых аналитическими пространствами - Analytic Workspace (AW). База данных может включать одно или более AW. Эти AW хранятся как BLOB в таблицах, специально названных с префиксом AW$.

Хотя кубы данных в Oracle Database не новы, в версиях, предшествующих Oracle Database 11g, доступ к ним выполнялся несколько иначе. (Ведь СУБД Oracle исходно и прежде всего реляционная СУБД.) Представление куба в этих версиях – это неродная (non-native) концепция, особенно, когда это затрагивает MV. MV обладают некоторыми интересными функциями: автоматическим переписыванием запроса (automatic query rewrite), когда пользовательский запрос переписывается автоматически, инкрементальные обновления, когда только части MV обновляются и так далее. С другой стороны, MV – это представление реляционной природы, неродное для OLAP-кубов.

Теперь представьте, если сможете, лучшее из этих двух миров: функция переписывания (rewrite feature) в MV, комбинируемая с преимуществами производительности OLAP-кубов. В Oracle Database 11g вы это имеете. Возможно, наиболее важной новой функциональностью в этой области является способность представлять OLAP-кубы как MV, благодаря новой функции, называемой Cube Organized Materialized Views – материализованные представления, организованные как кубы. Новая функция CUBE_TABLE реализует в кубе поиск, заданный на SQL. Поскольку это MV в действительности OLAP-куб, функция Query Rewrite перепишет запросы для использования куба, а вы об этом даже не узнаете. Это должно дать преимущество производительности кубов через использование любого средства, поддерживающего SQL: Oracle Business Intelligence Enterprise Edition, Cognos, Business Objects, Oracle Apex, SQL*Plus или заказные (custom) Java-программы; этот список бесконечен. Фактически, вы можете не знать какой-либо специальный синтаксис. (для облегчения идентификации Cube Organized MVs именуются с префиксом CB$.) Я поясню эту новую функциональность на примере официальной схемы Oracle. Скачав (downloading) ее, распакуйте следующий zip файл:

$ unzip global_11g_schema.zip
Archive:  global_11g_schema.zip
  inflating: global_11g_remove.sql   
  inflating: global_11g_source.dmp   
  inflating: Templates/CHANNEL.XML   
  inflating: Templates/CUSTOMER.XML  
  inflating: Templates/GLOBAL.XML    
  inflating: Templates/GLOBAL_MV.XML  
  inflating: Templates/PRICE_CUBE.XML  
  inflating: Templates/PRODUCT.XML   
  inflating: Templates/TIME.XML      
  inflating: Templates/UNITS_CUBE.XML  
  inflating: global_11g_install.sql  
  inflating: global_11g_readme.html  

Установите эту глобальную схему, прогнав следующий скрипт в SQL*Plus или SQL Developer. Вы должны знать пароль (password) пользователя SYSTEM:

SQL> @global_11g_install
Enter the password for the user GLOBAL: 
Enter the password for the user SYSTEM: 
Connected.
 
User created.
 
Grant succeeded.
 
Connected.
 
Import: Release 11.1.0.6.0 - Production on Sat Jun 28 17:08:22 2008
 
Copyright (c) 1982, 2007, Oracle.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
With the Partitioning, Oracle Label Security, OLAP, Data Mining, Oracle Database Vault and Real Application Testing options

Export file by EXPORT:V11.01.00 via conventional path import done in US7ASCII character set and AL16UTF16 NCHAR character set import server uses WE8MSWIN1252 character set (possible charset conversion) export client uses WE8MSWIN1252 character set (possible charset conversion) . importing GLOBAL's objects into GLOBAL

. . importing table                      "ACCOUNT"         24 rows imported
. . importing table                  "CHANNEL_DIM"          3 rows imported
. . importing table                 "CUSTOMER_DIM"         61 rows imported
. . importing table                   "PRICE_FACT"       2523 rows imported
. . importing table         "PRODUCT_CHILD_PARENT"         48 rows imported
. . importing table                  "PRODUCT_DIM"         36 rows imported
. . importing table                     "TIME_DIM"        120 rows imported
. . importing table                   "UNITS_FACT"     299446 rows imported
About to enable constraints...
Import terminated successfully without warnings.
 
SQL> exit

Файл global_11g_readme.html содержит много информации об этой схеме. Он также включает скрипт для удаления (drop) этой схемы после того, как тестирование завершено. Этот файл импортирует размерности, факты, и все другие необходимые данные из dump-файла. Наверное, легче всего объяснить концепцию Cube Organized MV на примере. Есть два куба, включенных в этот dump-файл; один – PRICE_CUBE. Рассмотрим, как запрашивать этот куб с применением SQL. Я также хочу показать путь доступа, который пройдет СУБД Oracle, поэтому я использовал команду autotrace перед выполнением этого запроса.

SQL> set autotrace on explain
SQL> select * from table(cube_table('GLOBAL.PRICE_CUBE'))
  2> /
 
...
... the data comes here ...
...
Execution Plan
----------------------------------------------------------
Plan hash value: 3184667476
 
--------------------------------------------------------------------------------------
| Id  | Operation               | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |            |  2000 |   195K|    29   (0)| 00:00:01 |
|   1 |  CUBE SCAN PARTIAL OUTER| PRICE_CUBE |  2000 |   195K|    29   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

Функция CUBE_TABLE появилась в Oracle Database 11g. Благодаря ей, к кубу, хранимому в AW, можно выдавать запросы как к реляционному объекту. Отметим, что путь доступа показывает функция CUBE SCAN, смысл которой в том, что этот куб просканирован именно как куб, даже если вы использовали SQL. В этом примере мы использовали самый древний из инструментов - SQL*Plus, который ничего не “знает" об OLAP или аналитических трансформациях, однако, мы смогли собрать нужные данные аналитическим способом.

Функция CUBE_TABLE может использоваться как с таблицами, так и с размерностями. Общий формат таков:

select * from table(cube_table('.;'))

Параметр hierarchy опционален; можно его не указывать. Это пример из схемы GLOBAL, которая была установлена ранее, в котором вы хотите выбрать иерархию PRIMARY из размерности PRODUCT.


select * from table(cube_table('GLOBAL.PRODUCT;PRIMARY'))

Для каждого куба и размерности генерируется представление, называемое PRICE_CUBE_VIEW для куба PRICE_CUBE. Если вы исследуете определение этого представления, то увидите его, как показано здесь:


CREATE OR REPLACE VIEW "PRICE_CUBE_VIEW" ("UNIT_PRICE", "UNIT_COST", "TIME", "PRODUCT") AS 
 SELECT 
    "UNIT_PRICE", 
    "UNIT_COST", 
    "TIME", 
    "PRODUCT"
  FROM TABLE(CUBE_TABLE('GLOBAL.PRICE_CUBE') ) 

Представления полезны тогда, когда GUI-инструменты не “знают" о функции CUBE и пользователям предлагают выбрать объектный тип, как правило представление. Вот пример, как Oracle SQL Developer используется для выборки данных из представления.

SQL Developer показывает эти представления и вы можете выбрать таблицу данных и фильтр как любое другое представление. Хотя тип данных (этой таблицы) – многомерный, функция таблицы CUBE_TABLE позволяет получать к ней (таблице) доступ как к реляционному объекту. А теперь рассмотрим, что можно получить от Cube Organized MV. Во-первых, куб (и MV, организованное как куб) может резко улучшить производительность запросов, требующих суммарные данные, благодаря аналитическому доступу к этому кубу. Во-вторых, куб весьма эффективен при быстрых, инкрементальных обновлениях. Наконец, так как один куб может заменить множество MV, то поддержка становится намного легче.

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

Частое переписывание запросов

Вы должны быть уже знакомы с функциональностью Query Rewrite, введенной в Oracle Database пару релизов назад. В целом, когда пользователь пишет запрос, который соответствует запросу, определяющему MV, СУБД Oracle выбирает выборку из MV вместо выполнения этого запроса на базе данных. Термин "matches" означает, что частичный набор результатов (partial result set) этого запроса может быть удовлетворен хранимым MV или же запрос (его выполнение) может быть ускорено при использовании существующих данных в конкретном MV. Иначе говоря, СУБД Oracle переписывает запрос (или части его), чтобы выбрать данные из MV вместо таблицы, указанной в этом запросе. Это исключает работу с базой данных и быстрее возвращает результат пользователю. Все это происходит автоматически, пользователь даже не знает ни о MV, ни о переписывании запроса.

Конечно, пользователь должен выбрать, принимать ли ему такую подстановку в запросе или нет. Параметр сессии query_rewrite_enabled должен быть установлен в TRUE и целостность переписывания запроса должна быть либо принята (query_rewrite_integrity равен tru), либо stale_tolerated указывает на устарелость (staleness) MV (это параметр контролирует уровень целостности данных, обеспечиваемый ядром). Само же MV должно быть также доступно для переписывания запроса. Переписывание запроса происходит, когда пользовательские запросы аналогичны запросу, определяющему MV. В прошлых версиях, если они не были аналогичны, переписывание не происходило. Но в Oracle Database 11g эти правила смягчены. Рассмотрим MV, показанное ниже:

create materialized view mv4
        enable query rewrite 
as
select   prod_id, cust_id, avg (rate) tot_qty
    from (select s.prod_id, cust_id, amount_sold / quantity_sold rate
            from sales s, products p
           where s.prod_id = p.prod_id) sq
group by prod_id, cust_id

/

Оно использует inline-запрос, в котором источником строк является другой запрос (фраза clause в FROM, фактически inline-запрос). Если вы пишите запрос аналогичный запросу, определяющему MV, в котором используете то же самое inline-представление, то можно увидеть переписывание. Используйте AUTOTRACE для проверки пути выполнения.


SQL> alter session set query_rewrite_enabled = true;
 
Session altered.
 
SQL> alter session set query_rewrite_integrity = stale_tolerated;
 
Session altered.

SQL> set autotrace traceonly explain
SQL> select pid, cid, avg(item_rate) avg_item_rate
  2  from (select s.prod_id pid, cust_id cid, amount_sold/quantity_sold item_rate
  3  from sales s, products p
  4  where p.prod_id = s.prod_id)
  5  group by cid, pid;
Execution Plan
----------------------------------------------------------
Plan hash value: 3944983699
 
-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |   287K|    10M|   226   (2)| 00:00:03 |
|   1 |  MAT_VIEW REWRITE ACCESS FULL| MV4  |   287K|    10M|   226   (2)| 00:00:03 |
-------------------------------------------------------------------------------------
 
Note
-----
   - dynamic sampling used for this statement

Отметим, что выше Id=1; запрос был переписан с Materialized View MV4— тем самым, который мы создали раньше. Переписывание запроса имело бы место, даже если бы это MV и запрос использовали inline-представления (или подзапросы).

Переписывание запроса в Oracle Database 11g происходит также и для удаленных таблиц.

Проверка устарелости в разделах

Если имеется секционированная детальная таблица, на которой было создано MV, то можно воспользоваться преимуществами особенности Partition Change Tracking (PCT; введенной в Oracle Database 10g) для обновления только заданной секции, а не всей таблицы. Особенность PCT позволяет обновлять с опцией FAST, даже если нет MV Log (журнала MV) на данной детальной таблице. Но как узнать, как изменились разделы?

В Oracle Database 11g появилось замечательное новое представление: DBA_MVIEW_DETAIL_PARTITION. Оно показывает разделы, которые были изменены и будут позднее использоваться в обновлении посредством PCT. Столбец FRESHNESS показывает, что данный раздел свеж для MV. Как и для любого другого представления, в данном случае также есть USER_* и ALL_* версии.

Давайте используем схему SH, предоставленную на Companion CD of Oracle Database 11g. Прежде всего, проверим свежесть:

SQL> select detailobj_name, detail_partition_name, detail_partition_position, freshness
  2> from user_mview_detail_partition
  3> where MVIEW_NAME = 'MV1';

DETAILOBJ_NAME                 DETAIL_PARTITION_NAME          DETAIL_PARTITION_POSITION FRESH
------------------------------ ------------------------------ ------------------------- -----
SALES                          SALES_1995                                             1 FRESH
SALES                          SALES_1996                                             2 FRESH
SALES                          SALES_H1_1997                                          3 FRESH
SALES                          SALES_H2_1997                                          4 FRESH
SALES                          SALES_Q1_1998                                          5 FRESH
SALES                          SALES_Q2_1998                                          6 FRESH
SALES                          SALES_Q3_1998                                          7 FRESH
SALES                          SALES_Q4_1998                                          8 FRESH
SALES                          SALES_Q1_1999                                          9 FRESH
SALES                          SALES_Q2_1999                                         10 FRESH
SALES                          SALES_Q3_1999                                         11 FRESH
SALES                          SALES_Q4_1999                                         12 FRESH
SALES                          SALES_Q1_2000                                         13 FRESH
SALES                          SALES_Q2_2000                                         14 FRESH
SALES                          SALES_Q3_2000                                         15 FRESH
SALES                          SALES_Q4_2000                                         16 FRESH
SALES                          SALES_Q1_2001                                         17 FRESH
SALES                          SALES_Q2_2001                                         18 FRESH
SALES                          SALES_Q3_2001                                         19 FRESH
SALES                          SALES_Q4_2001                                         20 FRESH
SALES                          SALES_Q1_2002                                         21 FRESH
SALES                          SALES_Q2_2002                                         22 FRESH
SALES                          SALES_Q3_2002                                         23 FRESH
SALES                          SALES_Q4_2002                                         24 FRESH
SALES                          SALES_Q1_2003                                         25 FRESH
SALES                          SALES_Q2_2003                                         26 FRESH
SALES                          SALES_Q3_2003                                         27 FRESH
SALES                          SALES_Q4_2003                                         28 FRESH

Теперь вставим строку в таблицу:

insert into sales values (13,987,'1-jan-98',3,999,1,1232.16)

А если сейчас запустить тот же самый запрос для проверки свежести:


DETAILOBJ_NAME                 DETAIL_PARTITION_NAME          DETAIL_PARTITION_POSITION FRESH
------------------------------ ------------------------------ ------------------------- -----
SALES                          SALES_1995                                             1 FRESH
SALES                          SALES_1996                                             2 FRESH
SALES                          SALES_H1_1997                                          3 FRESH
SALES                          SALES_H2_1997                                          4 FRESH
SALES                          SALES_Q1_1998                                          5 STALE
SALES                          SALES_Q2_1998                                          6 FRESH
... and so on ...

Раздел, в который попала строка —SALES_Q1_1998— теперь представлен как STALE. Когда вы сделаете быстрое обновление (fast refresh) этого MV, то PCT будет использоваться для обновления только этого раздела, а не из всей таблицы. И обновление FAST произойдет, даже если нет MV Log для этой таблицы.

Теперь, обновим MV с опцией FAST:

SQL> exec dbms_mview.refresh('MV1','F')
 
PL/SQL procedure successfully completed.

И проверим свежесть еще раз:


DETAILOBJ_NAME                 DETAIL_PARTITION_NAME          DETAIL_PARTITION_POSITION FRESH
------------------------------ ------------------------------ ------------------------- -----
SALES                          SALES_1995                                             1 FRESH
SALES                          SALES_1996                                             2 FRESH
SALES                          SALES_H1_1997                                          3 FRESH
SALES                          SALES_H2_1997                                          4 FRESH
SALES                          SALES_Q1_1998                                          5 FRESH
SALES                          SALES_Q2_1998                                          6 FRESH


Этот раздел теперь отмечен как FRESH; последующие быстрые обновления не затронут его. Это представление позволяет легко определять, какие разделы нужно обновлять с применением PCT, и оценить объем всей сопутствующей работы. Эта особенность работает также и для Cube Organized MVs. Analytic Workspace Manager – менеджер AW

Как я упоминал выше, специальная область, в которой хранятся OLAP-объекты, называется аналитическими пространствами - Analytic Workspace. С этими OLAP-объектами можно манипулировать посредством Analytic Workspace Manager (AWM), которое можно скачать с Oracle OLAP Option homepage на OTN. AWM поставляется в двух вариантах: автономная версия или DBClient. Автономная версия – это JAR-файл, который можно выполнять из командной строки java. В варианте DBClient есть несколько DLLs, которые должны быть скопированы в соответствующую директорию в Oracle Home. В этой секции мы рассмотрим автономную версию (11.1.0.7A) этого механизма.

После распаковки файлов стартуйте AWM, для этого перейдите в директорию, в которой он был распакован, и выдайте следующую команду:

java -mx512m -jar awm11.1.0.6.0A.jar

После открытия GUI-интерфейса, кликните по File -> Connect Database и выберите базу данных, с которой хотите соединиться. Выберите в качестве username - GLOBAL. Как только это соединение установлено, кликните по + знаку перед Schemas и раскройте все элементы. Результатом будет экран, показанный ниже.

Попробуем типичную операцию: обновление (refreshing) куба. Кликните справа по PRICE_CUBE на левой стороне панели. Меню, как всплывающее окно, появится как показано ниже:

Выберите Maintain Cube PRICE_CUBE из этого меню. Покажется маленькое окошко, как показано ниже:

Кликните по Next несколько раз и вы увидите экран, подобный этому:

Здесь можно выбрать – выполнять эту задачу сразу же или позднее по расписанию. Кликните Finish для завершения этой задачи. Постепенно вы увидите экран подтверждения, как показано ниже:

Отметим столбец OUTPUT, который показывает SQL-предложение. Дважды кликнув по нему, мы увидим полный результат. Результат для PRICE_CUBE показан ниже:

<CommandOutput>
<CubeLoad
Name="MAP1"
SQL="SELECT /*+  bypass_recursive_check  cursor_sharing_exact  no_expand */ 
  T16_MONTH_ID ALIAS_114, 
  T13_ITEM_ID ALIAS_115, 
  SUM(T19_UNIT_PRICE)  ALIAS_116, 
  SUM(T19_UNIT_COST)  ALIAS_117 
FROM 
  (
  SELECT 
    T1.ITEM_ID T19_ITEM_ID, 
    T1.MONTH_ID T19_MONTH_ID, 
    T1.UNIT_PRICE T19_UNIT_PRICE, 
    T1.UNIT_COST T19_UNIT_COST 
  FROM 
    GLOBAL.PRICE_FACT T1   ) 
  T19, 
  (
  SELECT 
    T1.MONTH_ID T16_MONTH_ID 
  FROM 
    GLOBAL.TIME_DIM T1   ) 
  T16, 
  (
  SELECT 
    T1.ITEM_ID T13_ITEM_ID 
  FROM 
    GLOBAL.PRODUCT_DIM T1   ) 
  T13 
WHERE 
  ((T16_MONTH_ID = T19_MONTH_ID) 
    AND (T13_ITEM_ID = T19_ITEM_ID) 
    AND (T16_MONTH_ID = T19_MONTH_ID) 
AND (T13_ITEM_ID = T19_ITEM_ID) )  
GROUP BY 
  (T13_ITEM_ID, T16_MONTH_ID)  
ORDER BY 
  T13_ITEM_ID ASC NULLS LAST , 
  T16_MONTH_ID ASC NULLS LAST "
LOADED="2523"
REJECTED="0"/>
</CommandOutput>

Другая важная задача – это сотворение MV из куба. Давайте посмотрим, как это делается для куба UNITS_CUBE. Кликните по UNITS_CUBE, который покажет подробности этого куба на панели справа. На этой панели вы увидите несколько таблиц. Кликните на таблице Materialized Views, как показано ниже:

Эта панель различных проверок, которые должны быть сделаны, прежде чем куб может быть сохранен как MV. Например, первая строка показывает "User must have create Materialized View Privilege" – пользователь должен создать привилегию для создания MV. Это объясняет самое себя. Пользователь должен иметь привилегию Create MV для создания MV. Проверка сделана и обнаружено, что пользователь действительно обладает этой привилегией. Этот статус показан как зеленая tick mark, означая, что условие удовлетворено.

Отметим следующее в верхнем левом углу этой панели:

Проверьте эту ячейку для обеспечения обновления куба в стиле MV. Затем проверьте ячейку Enable Query Rewrite внизу. Затем нажмите кнопку Apply. Куб теперь готов, как Cube Organized MV.

Теперь поскольку куб уже представлен как правильное MV, его можно обновить следующим образом.

 
begin
   dbms_mview.refresh (
       list => 'CB$PRICE_CUBE',
       method => 'c'
   );
end;

Можно также использовать подход с перестроением куба:

 
begin
   dbms_cube.build('PRICE_CUBE');
end;

После наполнения (populating) (или перестроения), вы должны собрать статистику:

begin
   dbms_aw_stats.analyze (
       'PRICE_CUBE'
   )
end;

Как я сказал ранее, AW хранятся как BLOB в базе данных. В этом примере:


SQL> desc aw$global
 Name                                      Null?    Type
 ----------------------------------------- -------- -----------------------
 PS#                                                NUMBER(10)
 GEN#                                               NUMBER(10)
 EXTNUM                                             NUMBER(8)
 AWLOB                                              BLOB
 OBJNAME                                            VARCHAR2(256)
 PARTNAME                                           VARCHAR2(256)

Столбец BLOB содержит данные этого куба. Итак, куб хранится в реляционной таблице в табличном пространстве, как любая другая таблица. Это пространство управляется как любое другое табличное пространство, так что АБД не должны делать что-то особенное после создания AW. Cube Organized MV таковы как любые другие MV, так что процесс обновления знаком большинству АБД.

Другие новые функции из других областей

В Oracle Database 11g есть еще несколько новых функций, которые полезны для эффективного проектирования и работы с хранилищами данных. Они рассматриваются в других статьях этой серии. Вместо повторения я дам их краткий обзор и направлю вас к соответствующим статьям за подробностями:

  • Partitioning (Секционирование). Oracle Database 11g предлагает новый тип диапазонного секционирования, названного Interval Partitioning, которое позволяет просто определять некоторое значение в виде интервала, — например, СУБД Oracle автоматически создает необходимые месячные секции на основе вставляемых записей. Секционирование другого типа, названное Reference Partitioning, позволяет создавать секции в подчиненных таблицах на основе значений в столбце родительской таблицы. Например, можно секционировать таблицу EMP в зависимости от местоположения департаментов, которое задается в родительской таблице (DEPT), но не в таблице EMP. Кроме того, теперь можно создавать композитные схемы секционирования (composite partitioning schemes) типа LIST-LIST, LIST-RANGE и RANGE-RANGE.
  • Virtual Columns (Виртуальные столбцы). Можно сделать столбец "virtual"; то есть, нехранимый в таблице, но пользователь получит к нему доступ как к любому другому столбцу. Значения этого столбца вычисляются во время выполнения. Например, виртуальный столбец COMMISSION может быть определен в таблице как вычисляемое значение комиссии в размере 20% от значения столбца SALARY (зарплата). На этом столбце можно определять индексы и даже разделы; СУБД собирает статистику этого виртуального столбца точно так как она делает это с обычными столбцами. В хранилище данных можно использовать виртуальный столбец для секционирования таблицы для отображения реальной жизни вместо (использования) реального столбца, тем самым экономя значительное пространство (на дисках). Если же вы обмениваетесь секциями с другой таблицей, то таблица не может иметь виртуальный столбец. Вам это понравится?
  • Advanced Compression (Продвинутое компрессирование). В дополнение к функциональности компрессирования в предыдущих версиях Oracle Database 11g предлагает новую опцию Advanced Compression – продвинутое компрессирование, которое работает иначе. Вместо компрессирования строки после ее ввода, компрессируется весь блок, когда в нем достигнуто некоторое пороговое значение. Это делает весь процесс чрезвычайно эффективным и приводит к значительным преимуществам в части пространства.
  • Pivot and Unpivot (Поворот и, конечно, разворот). Перекрестные отчеты типичны для любой системы репортинга, так как этот формат отчетов легко читать и данные хорошо представляются. В предыдущих релизах эти отчеты делались применением join-операции таблицы к самой себе столько раз, сколько есть столбцов. А это приводило к падению производительности запросов, особенно в хранилищах данных, в которых таблицы, как правило, велики. В Oracle Database 11g новый оператор, названный PIVOT (поворот) преобразует результат, который должен быть представлен в crosstab-формате. UNPIVOT (разворот) реализует преобразование данных в этом формате обратно в реляционный формат.
  • Partition Advisor (Советчик секционирования). Одной из ключевых проблем секционирования является определение столбцов, по которым оно будет производиться. Многие люди, даже те, кто этим периодически занимаются, не находят здесь лучших решений. Oracle Database 11g облегчает этот процесс, предоставляя новый инструмент Partition Advisor, который анализирует данные рабочей нагрузки и на этой основе предлагает схемы секционирования. Хотя это не на 100% превосходно, это определенно весьма существенная помощь для тех, кто не слишком силен в этой теме. А также начальная по меньшей мере точка для тех, у кого есть некоторый опыт.
  • Data Caching (Кэширование данных) Если данные меняются не часто, зачем обновлять их на диске? В Oracle Database 11g вы можете кэшировать результат запроса (но не таблицу) в специальном пуле оперативной памяти - Result Cache. Если же данные таблицы меняются, то автоматически изменится и пул – это своего рода самообновление представления в оперативной памяти. В этом пуле можно также кэшировать результаты PL/SQL-функции. Поскольку результаты выбираются из оперативной, а не дисковой памяти, время ответа будет намного меньше. В больших базах данных, таких как хранилища, в которых таблицы мало меняются для большинства запросов, можно кэшировать эти запросы и вызовы функций для выигрыша производительности.
  • Invisible Indexes (Невидимые индексы). Индексы можно сделать невидимыми. То есть, они не могут использоваться в путях доступа, если задан специальный параметр сессии. Однако, такой индекс поддерживается как нормальный индекс с соответствующим влиянием на производительность DML-операторов. Это хороший способ исследования их влияния. Если производительность не устраивает, индекс можно убрать.


    Arup Nanda

    Arup Nanda (arup@proligence.com) has been exclusively an Oracle DBA for more than 12 years with experiences spanning all areas of Oracle Database technology, and was named "DBA of the Year" by Oracle Magazine in 2003. Arup is a frequent speaker and writer in Oracle-related events and journals and an Oracle ACE Director. He co-authored four books, including RMAN Recipes for Oracle Database 11g: A Problem Solution Approach.

E-mail this page