Wenn man diese Tabellen aber denormalisiert (was im DWH-Kontext ja nicht unüblich ist), indem man sie mit dem Schlüssel der Tabelle mit den meisten Sätzen erweitert (im Beispiel DIM_VARIANTEN), dann erhält man eine 1:1-Beziehung zwischen allen Dimensionen. Wenn man dann zwischen den Schlüsselspalten noch wechselseitige Foreign Key-Beziehungen definiert, kann sich der Zugriff immer auf die jeweils relevante Datengrundlage beschränken:
-- Test_Join_Elimination.sql
-- Loeschung aller zugehoerigen Objekte
alter table dim_artikel drop constraint fk_a_v;
alter table dim_artikel drop constraint fk_a_s;
alter table dim_sortiment drop constraint fk_s_v;
alter table dim_sortiment drop constraint fk_s_a;
alter table dim_variante drop constraint fk_v_s;
alter table dim_variante drop constraint fk_v_a;
drop table dim_sortiment;
drop table dim_variante;
drop table dim_artikel;
-- Anlage der Dimensionstabellen mit jeweils 100M Saetzen
create table dim_variante tablespace test_ts
as
select rownum var_id
from dual
connect by level <= 100000;
create table dim_artikel tablespace test_ts
as
select rownum var_id
, substr(rownum, 1, 4) art_id
, mod(rownum, 4) + 1 saison
from dual
connect by level <= 100000;
create table dim_sortiment tablespace test_ts
as
select rownum var_id
, mod(rownum, 100) + 1 wgr_id
, 'WGR ' || to_char(mod(rownum, 100) + 1) wgr_name
from dual
connect by level <= 100000;
-- Anlage von PKs und FKs
alter table dim_variante add constraint pk_dim_variante primary key (var_id);
alter table dim_artikel add constraint pk_dim_artikel primary key (var_id);
alter table dim_sortiment add constraint pk_dim_sortiment primary key (var_id);
alter table dim_artikel add constraint fk_a_v foreign key (var_id) references dim_variante(var_id);
alter table dim_artikel add constraint fk_a_s foreign key (var_id) references dim_sortiment(var_id);
alter table dim_sortiment add constraint fk_s_v foreign key (var_id) references dim_variante(var_id);
alter table dim_sortiment add constraint fk_s_a foreign key (var_id) references dim_artikel(var_id);
alter table dim_variante add constraint fk_v_s foreign key (var_id) references dim_sortiment(var_id);
alter table dim_variante add constraint fk_v_a foreign key (var_id) references dim_artikel(var_id);
-- Statistikerhebung
exec dbms_stats.gather_table_stats(user, 'DIM_ARTIKEL')
exec dbms_stats.gather_table_stats(user, 'DIM_SORTIMENT')
exec dbms_stats.gather_table_stats(user, 'DIM_VARIANTE')
-- View-Anlage
create or replace view dim_variante_gesamt
as
select v.var_id
, a.art_id
, s.wgr_id
, s.wgr_name
, a.saison
from dim_variante v
, dim_sortiment s
, dim_artikel a
where v.var_id = a.var_id
and a.var_id = s.var_id;
-- Ermittlung der Pläne
explain plan for
select distinct saison
from dim_variante_gesamt;
select * from table(dbms_xplan.display(null, null, 'basic'));
explain plan for
select distinct wgr_name
from dim_variante_gesamt;
select * from table(dbms_xplan.display(null, null, 'basic'));
explain plan for
select distinct var_id
from dim_variante_gesamt;
select * from table(dbms_xplan.display(null, null, 'basic'));
explain plan for
select distinct wgr_name, saison
from dim_variante_gesamt;
select * from table(dbms_xplan.display(null, null, 'basic'));
Das Script liefert folgendes Ergebnis:
PLAN_TABLE_OUTPUT --------------------------------------------- Plan hash value: 1748037202 ------------------------------------------ | Id | Operation | Name | ------------------------------------------ | 0 | SELECT STATEMENT | | | 1 | HASH UNIQUE | | | 2 | TABLE ACCESS FULL| DIM_ARTIKEL | ------------------------------------------ PLAN_TABLE_OUTPUT --------------------------------------------- Plan hash value: 762726623 -------------------------------------------- | Id | Operation | Name | -------------------------------------------- | 0 | SELECT STATEMENT | | | 1 | HASH UNIQUE | | | 2 | TABLE ACCESS FULL| DIM_SORTIMENT | -------------------------------------------- PLAN_TABLE_OUTPUT --------------------------------------------- Plan hash value: 674027647 ------------------------------------------ | Id | Operation | Name | ------------------------------------------ | 0 | SELECT STATEMENT | | | 1 | TABLE ACCESS FULL| DIM_VARIANTE | ------------------------------------------ PLAN_TABLE_OUTPUT --------------------------------------------- Plan hash value: 1066181588 --------------------------------------------- | Id | Operation | Name | --------------------------------------------- | 0 | SELECT STATEMENT | | | 1 | HASH UNIQUE | | | 2 | HASH JOIN | | | 3 | TABLE ACCESS FULL| DIM_ARTIKEL | | 4 | TABLE ACCESS FULL| DIM_SORTIMENT | ---------------------------------------------
Demnach werden tatsächlich jeweils nur die Tabellen gelesen, die die erforderlichen Daten enthalten. Auf diese Weise kann man eine große Tabelle mit mehreren relativ unabhängigen Spaltengruppen (die ihrerseits eng miteinander zusammenhängen) in mehrere Segmente aufsplitten: also in gewisser Weise vertikal partitionieren. Allerdings wird in vielen Fällen die Verwendung geeigneter Indizes wahrscheinlich die näher liegende Vorgehensweise sein. Nachdem ich dieses Beispiel gebastelt hatte, kam mir dann auch noch der Gedanke, an den üblichen Stellen nach ähnlichen Beispielen zu suchen - und wahrscheinlich hält sich die Überraschung in Grenzen, wenn ich verrate, dass der Herr Kyte etwas Passendes im Angebot hat.
Keine Kommentare:
Kommentar veröffentlichen