2008年12月20日土曜日

[Oracle]Materialized ViewのORA-12899

▼問題
特定の条件を満たすと、Materialized Viewリフレッシュ時にORA-12899: 列 string の値が大きすぎます(実際: string、最大: string)が発生する。

▼対処方法
元表の項目桁数変更時はMaterialized Viewを再作成することで回避可能。

▼原因
Materialized View作成後、元表の項目桁数を拡張した際に発生する。これは、Materialized Viewの項目定義が、元表変更後の項目と一致しないために発生するようである。代表として桁数の観点で検証を実施したが、桁数以外にも当てはまると思われる。(例えば、Materialized Viewのカラム宣言でSELECT * ~を指定している場合など)

▼再現手順
--テーブル作成
create table tab(
col1 varchar2(1)
);


--データ投入
insert into tab
(col1)
values
('A')
;


--Materialized Viewを作成する
create materialized view mv_tab
refresh with rowid
as
select * from tab;


--この段階ではリフレッシュ可能である
begin dbms_mview.refresh('mv_tab'); end;
/
PL/SQLプロシージャが正常に完了しました。


--元表の定義を変更する
alter table tab modify(col1 varchar2(2));


--この時点でもリフレッシュ可能である
begin dbms_mview.refresh('mv_tab'); end;
/
PL/SQLプロシージャが正常に完了しました。


--データを変更する(1桁→2桁)
update tab
set col1 = 'AB'
;


--この時点でリフレッシュ不可能となる
begin dbms_mview.refresh('mv_tab'); end;
/

begin dbms_mview.refresh('mv_tab'); end;
*
行1でエラーが発生しました。:
ORA-12008: マテリアライズド・ビューのリフレッシュ・パスでエラーが発生しました。
ORA-12899: 列"FXUSER"."MV_TAB"."COL1"の値が大きすぎます(実際: 2、最大: 1)
ORA-06512: "SYS.DBMS_SNAPSHOT", 行2255
ORA-06512: "SYS.DBMS_SNAPSHOT", 行2461
ORA-06512: "SYS.DBMS_SNAPSHOT", 行2430
ORA-06512: 行1



[Appendix]
USER_TAB_COLUMNS表を確認したところ、Materialized Viewは実体表なので、内部的にはテーブルとして存在しているらしく、Materialized Viewと同名のオブジェクトが存在した。Materialized Viewのリフレッシュ時にはINSERTを実行しているため、トレースするまでもなくTAB→MV_TABへのデータ伝播(INSERT)の際に標記のエラーが発生したと見て間違いなさそうだ。
定義は以下の通り。

★エラーが発生しないときの定義
TABLE_NAME COLUMN_NAME DATA_LENGTH
----------- -------------- -----------
MV_TAB COL1 1
TAB COL1 1

★エラーが発生したときの定義
TABLE_NAME COLUMN_NAME DATA_LENGTH
----------- -------------- -----------
MV_TAB COL1 1
TAB COL1 2