web-dev-qa-db-ja.com

dbms_redefinitionを使用した後、SQL * Plusのdescテーブルにnullでない制約が表示されないのはなぜですか

再定義したい次の表があります。

_create table tq84_redefinition (
  id number primary key,
  ts1 timestamp not null,
  ts2 timestamp
);
_

列_not null_の_ts1_制約に注意してください。

_dbms_redefinition_を使用して、特に_copy_constraints => true_を使用します。

_create table tq84_redefinition_int (
    id number,                            -- Note: no primary key to prevent «ORA-01408: such column list already indexed»
    ts1 date,
    ts2 date,
    duration_minutes as ((ts2 - ts1) * 24 * 60)
);


begin
  dbms_redefinition.start_redef_table(
    user, 'tq84_redefinition', 'tq84_redefinition_int',
   'id, '               ||
   'to_date(to_char(ts1, ''ddmmyyyyhh24miss''), ''ddmmyyyyhh24miss'') ts1, ' ||
   'to_date(to_char(ts2, ''ddmmyyyyhh24miss''), ''ddmmyyyyhh24miss'') ts2');
end;
/



-- set serveroutput on

declare  
  cnt_errors binary_integer;
begin

  dbms_redefinition.copy_table_dependents(
    user, 'tq84_redefinition', 'tq84_redefinition_int', 
    -------------------------------------------------------
    copy_indexes     => dbms_redefinition.cons_orig_params,
    copy_triggers    => true, 
    copy_constraints => true, 
    copy_privileges  => true, 
    ignore_errors    => false, 
    num_errors       => cnt_errors,
    copy_statistics  => true, 
    copy_mvlog       => false);

  if cnt_errors > 0 then
     dbms_output.put_line('There were ' || cnt_errors || ' errors.');
  end if;

end;
/

exec dbms_redefinition.sync_interim_table(user, 'tq84_redefinition', 'tq84_redefinition_int');
exec dbms_redefinition.finish_redef_table(user, 'tq84_redefinition', 'tq84_redefinition_int');
_

SQL * Plusのdescが_not null_制約を正しく表示しないことを除いて、すべてが正常に機能しているようです。

_...> desc tq84_redefinition;
 Name                        Null?    Type
 --------------------------- -------- ---------------
 ID                                   NUMBER
 TS1                                  DATE
 TS2                                  DATE
 DURATION_MINUTES                     NUMBER
_

ただし、どこかに、null以外の制約が設定されています。を発行してそれを見ることができます

_select constraint_type, constraint_name, search_condition
  from user_constraints
 where table_name = 'TQ84_REDEFINITION';
_

また、レコード[insert into tq84_redefinition (id) values (999999)]を挿入しようとすると、(正しい)エラーメッセージORA-01400: cannot insert NULL into ("META"."TQ84_REDEFINITION"."TS1")が表示されます。

編集:バージョン(v $ version)は次のとおりです。

_BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
_

編集2 @Munchi、提案されたselectステートメントの結果

_select 
  column_name as "Name",
  nullable as "Null?",
  concat(concat(concat(data_type,'('),data_length),')') as "Type"
from
  user_tab_columns
where
  table_name = 'TQ84_REDEFINITION'
_

です

_Name                           N Type
------------------------------ - --------------
ID                             Y NUMBER(22)
TS1                            Y DATE(7)
TS2                            Y DATE(7)
DURATION_MINUTES               Y NUMBER(22)
_
5

これは既知のバグです(説明は残念ながら公開されていません):

Bug:4396234 ET10.2OREDEF:* _TAB_COLUMNSテーブルのNULL可能なCOLはオンラインREDEF後に更新されません

NOT NULL制約はNOVALIDATEとしてコピーされ、手動でVALIDATE状態に設定する必要があります。例:

ALTER TABLE t84_redefenition ENABLE VALIDATE CONSTRAINT constraint_name;

主な主要な問題は同様ですが、そのために報告されたバグはありません。ただし、無効にして再度有効にすると問題が解決することを発見しました。

ALTER TABLE t84_redefinition DISABLE PRIMARY KEY;
ALTER TABLE t84_redefinition ENABLE PRIMARY KEY;
11
Balazs Papp

テーブル列定義の_Not Null_句は、_$sys$cols_にフラグを設定し、列に_sys_xxxxxx_制約を生成します。

_dbms_redef_は、_sys_xxxxxxx_制約をコピーするだけで、フラグの設定を省略します。 「Nullable?」にデコードされるのはこのフラグです。テーブルのSQLDeveloper列タブに(たとえば)表示します。

これの効果は何ですか-

まあ、参照整合性は維持されます-制約が存在する列にnullを挿入しようとしても失敗します。

ただし、CBOが特定のクエリの最適化の一部として_$sys$cols_フラグ(制約ではない)を調べることをどこかで読みました(その記事をもう一度見つける必要があります)。

Null以外の列に基づくインデックスについて考えます。このインデックスは、FTSを実行するのではなく、select count(*)タイプのクエリを満たす候補になる場合があります。 _$sys$cols_自体がnull(再定義によって設定されない)の場合、そのインデックスは考慮されません。

あなたの再定義コードにステップを追加する努力の価値があると思います

再定義後-制約からnullでないcolの名前を保存します
-nullではない制約を削除-_alter table modify col not null_句で再適用

Java開発者のうめき声を静めるためでさえ、前と後の違いを見つけます。

1
GeeTee