sql >> Databáze >  >> RDS >> Oracle

Proč sem Oracle přidává skrytý sloupec?

Ve verzi Oracle 11g Oracle zavedl novou optimalizační techniku ​​pro zlepšení výkonu DDL operací. Tato nová funkce umožňuje extrémně rychlou dobu provádění při přidání NOT NULL sloupec s výchozí hodnotou do existující tabulky. Od verze 12c byla optimalizace DDL rozšířena o NULL sloupce s výchozí hodnotou.

Zvažte následující testovací tabulku s 1 000 000 řádky:

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

Nyní přidáme další nenulový sloupec s výchozí hodnotou v různých relacích pro 11g a 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

Všimněte si rozdílu v době provádění:1M řádků aktualizováno za 5 ms!?

Prováděcí plán ukazuje:

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

Prováděcí plán na 12c ukazuje na rozdíl od 11g složitou predikátovou část obsahující nový interní sloupec SYS_NC00006$ .

Tento predikát naznačuje, že Oracle interně stále zvažuje sloupec B jako potenciálně schopný obsahovat jiné než výchozí hodnoty. To znamená - Oracle nejprve fyzicky neaktualizuje každý řádek s výchozí hodnotou.

Proč nový interní sloupec SYS_NC00006$ je vytvořen?

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              

Všimněte si rozdílu v hodnotách B a souvisejících interních sloupcích. Oracle jednoduše kontroluje svůj interní sloupec vygenerovaný systémem (např. SYS_NC00006$ ) a prostřednictvím SYS_OP_VECBIT zda se má vzít v úvahu výchozí hodnota sloupce B nebo reálná hodnota upravená pomocí explicitního příkazu DML.

Co je to se dvěma samostatnými alter prohlášeními?

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

Hodnota nového sloupce zůstává NULL pro všechny řádky. Nejsou potřeba žádné skutečné aktualizace, proto příkaz DDL nebude optimalizován.

Zde je článek OTN, který podrobněji vysvětluje novou optimalizaci DDL.




  1. Aktualizace div při kliknutí na tlačítko, když je tlačítko vygenerováno kliknutím na jiné tlačítko

  2. Přidání posunu časového pásma k hodnotě datetime2 v SQL Server (T-SQL)

  3. Jak vygenerovat náhodné číslo bez opakování v databázi pomocí PHP?

  4. použití GROUP BY v mysql 8