Oracle
 sql >> база данни >  >> RDS >> Oracle

Защо Oracle добавя скрита колона тук?

В версия 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 оптимизация.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Известие за промени в таблицата на Oracle в Java

  2. Непренебрежимо малка разлика в плана за изпълнение с Oracle при използване на jdbc Timestamp или Date

  3. RAC последователност Contention

  4. Как да изведем резултат от оператор SELECT, който се изпълнява с помощта на естествен динамичен SQL?

  5. Как да изпълните PL SQL блок в Oracle