Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Warum fügt Oracle hier eine versteckte Spalte hinzu?

In Oracle Release 11g hat Oracle eine neue Optimierungstechnik zur Verbesserung der Leistung von DDL-Operationen eingeführt. Diese neue Funktion ermöglicht eine extrem schnelle Ausführungszeit beim Hinzufügen von NOT NULL Spalte mit Standardwert zu einer bestehenden Tabelle hinzufügen. Seit Release 12c wurde die DDL-Optimierung um NULL erweitert Spalten mit Standardwert.

Betrachten Sie folgende Testtabelle mit 1.000.000 Zeilen:

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

Jetzt fügen wir eine zusätzliche Nicht-Null-Spalte mit einem Standardwert in verschiedenen Sitzungen für 11g und 12c hinzu:

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

Beachten Sie den Unterschied in der Ausführungszeit:1 Mio. Zeilen werden in 5 ms aktualisiert!?

Ausführungsplan zeigt:

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

Der Ausführungsplan auf 12c zeigt im Gegensatz zu 11g einen komplexen Prädikatsteil mit einer neuen internen Spalte SYS_NC00006$ .

Dieses Prädikat zeigt an, dass Oracle intern immer noch davon ausgeht, dass die B-Spalte möglicherweise nicht standardmäßige Werte enthalten kann. Dies bedeutet, dass Oracle zunächst nicht jede Zeile physisch mit dem Standardwert aktualisiert.

Warum eine neue interne Spalte SYS_NC00006$ geschaffen?

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              

Beachten Sie den Unterschied in den Werten von B und verwandten internen Spalten. Oracle prüft einfach seine vom System generierte interne Spalte (z. B. SYS_NC00006$ ) und über den SYS_OP_VECBIT Funktion, ob der Standardwert der B-Spalte oder der reale Wert berücksichtigt werden soll, der über eine explizite DML-Anweisung geändert wurde.

Was ist mit zwei getrennten Alter-Anweisungen?

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

Der Wert der neuen Spalte bleibt für alle Zeilen NULL. Es sind keine wirklichen Updates erforderlich, daher wird die DDL-Anweisung nicht optimiert.

hier ist ein OTN-Artikel, der die neue DDL-Optimierung näher erläutert.