Godiva,
tak pod dlouhé době zase nějaký post. Ne, že bych snad něměl nápady, co sem spát, ale prostě není čas -ale i takto tu tak nějak hodlám tento rok udržovat Inu, dnešní téma je DEFAULT na 12c a nová featura/optimalizace Oracle, která nás tak trošku potrápila, ale ve skutečnosti je neskutečně sexy.
Kolega nedávno objevil záhadný hidden sloupec v tabulce (a tudíš jemu patří credit) a ptal se jak se tam sakra dostal. Popravdě Oracle 12c si vlastní systémové sloupce přidává docela rád a ne vždy to člověka potěší. Při takovém SWITCH PARTITIONS to nepotěší nikdy Nicméně, na otázku kolegy jsem mu nabídl vysvětlení extended statistic, Oracle 12c (v defaulutu zapnuto) si pro korelované sloupce v predikátech založí virtuální sloupec a nad nim spočitá statistiky. Což se nepotvrdilo. Určit exaktně o co přesně jde z následující tabulky:
<code> property number not null, /* column properties (bit flags): */
/* 0×0001 = 1 = ADT attribute column */
/* 0×0002 = 2 = OID column */
/* 0×0004 = 4 = nested table column */
/* 0×0008 = 8 = virtual column */
/* 0×0010 = 16 = nested table’s SETID$ column */
/* 0×0020 = 32 = hidden column */
/* 0×0040 = 64 = primary-key based OID column */
/* 0×0080 = 128 = column is stored in a lob */
/* 0×0100 = 256 = system-generated column */
/* 0×0200 = 512 = rowinfo column of typed table/view */
/* 0×0400 = 1024 = nested table columns setid */
/* 0×0800 = 2048 = column not insertable */
/* 0×1000 = 4096 = column not updatable */
/* 0×2000 = 8192 = column not deletable */
/* 0×4000 = 16384 = dropped column */
/* 0×8000 = 32768 = unused column – data still in row */
/* 0×00010000 = 65536 = virtual column */
/* 0×00020000 = 131072 = place DESCEND operator on top */
/* 0×00040000 = 262144 = virtual column is NLS dependent */
/* 0×00080000 = 524288 = ref column (present as oid col) */
/* 0×00100000 = 1048576 = hidden snapshot base table column */
/* 0×00200000 = 2097152 = attribute column of a user-defined ref */
/* 0×00400000 = 4194304 = export hidden column,RLS on hidden col */
/* 0×00800000 = 8388608 = string column measured in characters */
/* 0×01000000 = 16777216 = virtual column expression specified */
/* 0×02000000 = 33554432 = typeid column */
/* 0×04000000 = 67108864 = Column is encrypted */
/* 0×20000000 = 536870912 = Column is encrypted without salt */
/* 0×000800000000 = 34359738368 = default with sequence */
/* 0×001000000000 = 68719476736 = default on null */
/* 0×002000000000 = 137438953472 = generated always identity column */
/* 0×004000000000 = 274877906944 = generated by default identity col */
/* 0×080000000000 = 8796093022208 = Column is sensitive */
</code>
No dobře, neni to přesně tabulka, ale jsou to vykopírované komentáře z rdbms/admin/dcore.bsq. A obecně jsou tyto typy souboru (admin/*.bsq) vhodné pro zkoumání, co která hodnota PROPERTY asi tak znamená (pro mně novinka).
Zkrátka jsme po chvíli přišli na to, že se jednalo o přidání sloupce s DEFALUTEM na NULLABLE sloupec – zatímco v 11g si Oracle musí naupdatovat všechny řádky s novou DEFULAT hodnotou, na 12c se jedná pouze o změnu definici tabulky a běh v řádu častí sekundy – ovšem za cenu nového hidden sloupce, který nyní udržuje informaci, zda-li je v řádku reálně NULL nebo DEFAULT hodnota. Krásný článek je o tom přímo u Oracle: http://www.oracle.com/technetwork/articles/database/ddl-optimizaton-in-odb12c-2331068.html. Který navíc krásně popisuje jak to pak funguje, když se na sloupec dotazuji (použití NVL na určení, co je je opravdová hodnota).
Takže zkouška:
CREATE TABLE T_TEST(a VARCHAR2(1), b VARCHAR2(2));
INSERT INTO T_TEST VALUES ('a', 'b');
INSERT INTO T_TEST VALUES ('a', 'b');
INSERT INTO T_TEST VALUES ('a', 'b');
ALTER TABLE T_TEST ADD (c VARCHAR2(1) DEFAULT 'z');
INSERT INTO T_TEST(a,b,c) VALUES ('a', 'b',null);
INSERT INTO T_TEST(a,b,c) VALUES ('a', 'b',null);
INSERT INTO T_TEST(a,b,c) VALUES ('a', 'b',null);
A nyní pohled na data (s jedním řádkem, před přidáním constrainu):
V tabulce je nově sloupce SYS_N00003$, který určuje, jestli se jedná reálně o NULL, nebo o sloupec ve kterém byl NULL před přidáním constrainu a tudíš by nyní měl obsahovat “z”. Oracle na to musí aplikovat funkce a rozhodnout, která hodnota je tedyy platná – ve sloupci C/default či SYS_N00003$. Jak to dělá ukazuje linknutý článek na Oracle.com – co je nutné podotknout, není to vidět před spuštěním ale až v reálném exekučním plánu. Článek to ukazuje na predikátu, ale stačí kouknout do PROJECTION : DECODE(TO_CHAR(SYS_OP_VECBIT(“SYS_NC00003$”,0)),NULL,NVL(“C”,’z’),’0′,NVL(“C”,’z’),’1′,”C”). A to samé si pak mohu použít v SQL:
Jak se toho zbavit?
Expost, popravdě nevím – sloupec nelze droponout (ORA-14148) a ani s pár pokusama změnit pod system PROPERTY jsem neuspěl :(. Nicméně jedná se o novinku a obyčejně Oracle “somehow” umožňuje nové chování potlačit. Obyčejně se jedná o zkryté parametry. Což se hledá velice špatně – většinou řeším LIKE + kombinace s hodnotou o které si myslím, že je právě nastavena. Tedy zkrytý parametr obsahující slovo NULL, který je nastaven na TRUE:
select * from (
;
SELECT
a.ksppinm Param ,
b.ksppstvl SessionVal ,
c.ksppstvl InstanceVal,
a.ksppdesc Descr
FROM
x$ksppi a ,
x$ksppcv b ,
x$ksppsv c
WHERE
a.indx = b.indx AND
a.indx = c.indx AND
a.ksppinm LIKE '/_%' escape '/'
AND b.ksppstvl='TRUE'
ORDER BY
1)
where upper(descr) like '%NULL%'
S tím, že mi to našlo celkem 5 parametrů. Většina se týká joinu a pak _add_nullable_column_with_default_optim. Tento zkrytý parametr je možné nastavit i na úrovni session i na úrovni instance a neni statistký. Sice nepodporovaný, ale když si před přidáním DEFAULT hodnoty na NULLABLE sloupce vylatrujete session :
alter system set "_add_nullable_column_with_default_optim"=false;
So, nepříjemnost při SWITCHOVÁNÍ PARTITIONS či použití ALL_TAB_COLS místo ALL_TAB_COLUMNS nebo sexy věc při přidání DEFAULTu na sloupec (nyní nově na nullable sloupec) v tabulce s 100mil záznamy a během v řádu desetin sekundy Podle toho, kdo jste