В версия 11g на Oracle Oracle въведе нова техника за оптимизация за подобряване на производителността на 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:
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
Забележете разликата във времето за изпълнение:1M редове се актуализират за 5 ms!?
Планът за изпълнение показва:
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 оператор.
Какво става с два отделни израза за промяна?
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 изразът няма да бъде оптимизиран.
Тук е OTN статия, която обяснява по-подробно новата DDL оптимизация.