sql >> Base de Datos >  >> RDS >> Oracle

¿Por qué Oracle agrega una columna oculta aquí?

En la versión 11g de Oracle, Oracle introdujo una nueva técnica de optimización para mejorar el rendimiento de las operaciones DDL. Esta nueva característica permite un tiempo de ejecución extremadamente rápido al agregar un NOT NULL columna con valor predeterminado a una tabla existente. Desde la versión 12c, la optimización DDL se ha ampliado para incluir NULL columnas con valor predeterminado.

Considere la siguiente tabla de prueba con 1.000.000 filas:

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

Ahora vamos a agregar una columna adicional no nula que tiene un valor predeterminado en diferentes sesiones para 11g y 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

Observe la diferencia en el tiempo de ejecución:1 millón de filas actualizadas en 5 ms.

El plan de ejecución muestra:

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

El plan de ejecución en 12c muestra, en contraste con 11g, una parte de predicado compleja que involucra una nueva columna interna SYS_NC00006$ .

Este predicado indica que, internamente, Oracle todavía está considerando que la columna B puede contener valores no predeterminados. Significa:Oracle al principio no actualiza físicamente cada fila con el valor predeterminado.

Por qué una nueva columna interna SYS_NC00006$ ¿es creado?

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              

Observe la diferencia en los valores de B y las columnas internas relacionadas. Oracle simplemente está revisando su columna interna generada por el sistema (por ejemplo, SYS_NC00006$ ) y a través de SYS_OP_VECBIT función si considerar el valor predeterminado de la columna B o el valor real modificado a través de una declaración DML explícita.

¿Qué pasa con dos declaraciones alter separadas?

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

El valor de la nueva columna sigue siendo NULL para todas las filas. No se necesitan actualizaciones reales, por lo tanto, la declaración DDL no se optimizará.

Aquí es un artículo de OTN que explica la nueva optimización de DDL con más detalle.