Oracle
 sql >> Database >  >> RDS >> Oracle

Perché Oracle aggiunge una colonna nascosta qui?

Nella versione 11g di Oracle Oracle ha introdotto una nuova tecnica di ottimizzazione per migliorare le prestazioni delle operazioni DDL. Questa nuova funzionalità consente tempi di esecuzione estremamente rapidi quando si aggiunge un NON NULL colonna con valore predefinito in una tabella esistente. Dalla versione 12c l'ottimizzazione DDL è stata estesa per includere NULL colonne con valore predefinito.

Considera la seguente tabella di test con 1.000.000 di righe:

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); 

Ora aggiungeremo una colonna extra non nulla con un valore predefinito in sessioni diverse per 11g e 12c:

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

Notare la differenza nel tempo di esecuzione:1 milione di righe aggiornate in 5 ms!?

Il piano di esecuzione mostra:

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

Il piano di esecuzione su 12c mostra per contrasto con 11g una parte predicativa complessa che coinvolge una nuova colonna interna SYS_NC00006$ .

Questo predicato indica che, internamente, Oracle sta ancora considerando la colonna B come potenzialmente in grado di contenere valori non predefiniti. Significa che all'inizio Oracle non aggiorna fisicamente ogni riga con il valore predefinito.

Perché una nuova colonna interna SYS_NC00006$ è creato?

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              

Notare la differenza nei valori di B e delle relative colonne interne. Oracle sta semplicemente controllando attraverso la sua colonna interna generata dal sistema (ad es. SYS_NC00006$ ) e tramite il SYS_OP_VECBIT funzione se considerare il valore di default della colonna B o il valore reale modificato tramite un'esplicita istruzione DML.

Che cos'è con due alter dichiarazioni separate?

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

Il valore della nuova colonna rimane NULL per tutte le righe. Non sono necessari veri e propri aggiornamenti, pertanto l'istruzione DDL non sarà ottimizzata.

Qui è un articolo OTN che spiega più dettagliatamente la nuova ottimizzazione DDL.