sql >> データベース >  >> RDS >> Oracle

Oracleがここに非表示の列を追加するのはなぜですか?

    Oracleリリース11gでは、オラクルはDDL操作のパフォーマンスを改善するための新しい最適化手法を導入しました。この新機能により、 NOT NULLを追加するときに非常に高速な実行時間が可能になります 既存のテーブルのデフォルト値を持つ列。リリース12c以降、DDL最適化が拡張されて NULLが含まれるようになりました デフォルト値の列。

    1.000.000行の次のテストテーブルを検討してください。

    sql> create table xxy
    as select rownum a from dual connect by level <= 1e6
    ;
    sql> select /*+ gather_plan_statistics */ count(1) from xxy;
    sql> select * from table(dbms_xplan.display_cursor); 
    

    次に、11gと12cのさまざまなセッションで、デフォルト値を持つnull以外の列を追加します。

    11g> alter table xxy add b number default 1;
         --Table XXY altered. Elapsed: 00:01:00.998
    
    12c> alter table xxy add b number default 1;
         --Table XXY altered. Elapsed: 00:00:00.052
    

    実行時間の違いに注意してください:5ミリ秒で100万行が更新されました!?

    実行計画は次のことを示しています:

    11g> select count(1) from xxy where b = 1;
      COUNT(1)
    ----------
       1000000
    11g> select * from table(dbms_xplan.display_cursor);
    ---------------------------------------------------------------------------
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |      |       |       |  1040 (100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |    13 |            |          |
    |*  2 |   TABLE ACCESS FULL| XXY  |   898K|    11M|  1040   (1)| 00:00:13 |
    ---------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       2 - filter("B"=1)
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    12c> select count(1) from xxy where b = 1;
    12c> select * from table(dbms_xplan.display_cursor);
    ---------------------------------------------------------------------------
    | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |      |       |       |   429 (100)|          |
    |   1 |  SORT AGGREGATE    |      |     1 |     5 |            |          |
    |*  2 |   TABLE ACCESS FULL| XXY  |  1000K|  4882K|   429   (2)| 00:00:01 |
    ---------------------------------------------------------------------------
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       2 - filter(DECODE(TO_CHAR(SYS_OP_VECBIT("SYS_NC00002$",0)),NULL,NVL("
                  B",1),'0',NVL("B",1),'1',"B")=1)
    Note
    -----
       - statistics feedback used for this statement
    

    12cの実行プランは、11gとは対照的に、新しい内部列SYS_NC00006$を含む複雑な述語部分を示しています。 。

    この述語は、内部的には、OracleがB列にデフォルト以外の値を含めることができる可能性があるとまだ検討していることを示しています。つまり、Oracleは最初、各行をデフォルト値で物理的に更新しません。

    新しい内部列SYS_NC00006$が選ばれる理由 創造された?

    12c> select column_name, virtual_column, hidden_column, user_generated 
    from user_tab_cols
    where table_name = 'XXY'
    ;
    COLUMN_NAME      VIR HID USE
    ---------------- --- --- ---
    B                NO  NO  YES
    SYS_NC00002$     NO  YES NO 
    A                NO  NO  YES
    
    12c> select a, b, SYS_NC00002$ hid from xxy where a in (1,10);
    
            A          B HID            
    ---------- ---------- ----------------
             1          1                 
            10          1                 
    
    12c> update xxy set b=1 where a=10 and b=1;
    1 row updated.
    
    12c> select a, b, SYS_NC00002$ hid from xxy where a in (1,10);
             A          B HID            
    ---------- ---------- ----------------
             1          1                 
            10          1 01              
    

    Bと関連する内部列の値の違いに注意してください。 Oracleは、システムで生成された内部列(SYS_NC00006$など)をチェックしているだけです。 )およびSYS_OP_VECBITを介して B列のデフォルト値を考慮するか、明示的なDMLステートメントを介して変更された実際の値を考慮するかを機能させます。

    2つの別々のalterステートメントとは何ですか?

    12c> alter table xxy add (b integer);
    12c> alter table xxy modify b default 1;
    
    12c> select count(b), count(coalesce(b,0)) nulls  from xxy where b = 1 or b is null;
    
      COUNT(B)      NULLS
    ---------- ----------
             0    1000000
    

    新しい列の値は、すべての行でNULLのままです。実際の更新は必要ないため、DDLステートメントは最適化されません。

    こちら は、新しいDDL最適化をより詳細に説明するOTNの記事です。




    1. 列/IDの最後の桁に基づくMysqlテーブルパーティション

    2. SQL Server 2008 R2でCONCAT関数を使用するにはどうすればよいですか?

    3. クエリ内のMySQLgroup_concat_max_len

    4. MySQLCLIより400倍長いPDOステートメント