Mám rozdělenou tabulku pro protokolování některých aplikací. Před několika lety jsem rozdělil tabulku na jeden oddíl za měsíc. Jak se blíží rok 2016, je čas, abych přidal oddíly pro nový rok. Dělená tabulka má jako poslední dva oddíly oddíl pro prosinec 2015 a oddíl používající MAXVALUE. Nikdy neplánuji mít žádná data v oddílu MAXVALUE. Je tu jen pro usnadnění operací SPLIT PARTITION.
V minulosti bych přidával oddíly s příkazy podobnými následujícímu:
ALTER TABLE usage_tracking
SPLIT PARTITION usage_tracking_pmax AT (TO_DATE('02/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS))
INTO (PARTITION usage_tracking_p201601, PARTITION usage_tracking_pmax);
ALTER TABLE usage_tracking
SPLIT PARTITION usage_tracking_pmax AT (TO_DATE('03/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS'))
INTO (PARTITION usage_tracking_p201602, PARTITION usage_tracking_pmax);
Výše uvedené příkazy SQL rozdělí oddíl MAXVALUE na dva oddíly. Existuje 12 takových příkazů, jeden pro každý měsíc.
Když jsem se letos pokusil spustit skript pro rok 2016 v neprodukčním prostředí, překvapilo mě, že dokončení těchto příkazů trvalo asi 30 minut. V předchozích letech dokončili během několika sekund. Pamatujte, že USAGE_TRACKING_PMAX je prázdné, takže není třeba přesouvat žádná data do příslušného oddílu.
Při analýze aktivity mé relace provádějící SPLIT jsem jasně viděl události čekání na soubor db, které byly sledovány do této rozdělené tabulky. Bylo zřejmé, že operace SPLIT načítá maximální oddíl, i když byl prázdný.
Předchozí roky fungovaly dobře, ale tato databáze byla nedávno upgradována na Oracle 12c. Informace o tom, jak provést operaci rychlého rozdělení oddílu, jsem našel v MOS Note 1268714.1, který říká, že to platí pro Oracle 10.2.0.3 a vyšší, ale v 11.2.0.4 jsem neměl žádné problémy. Pravděpodobně to bylo jen hloupé štěstí a nemám 11g databázi, na které bych to mohl zkontrolovat, protože všechny moje byly upgradovány. Místo toho, abych se zaměřoval na to, co se změnilo, prostě vyřeším problém a budu pokračovat ve svém dni.
Podle poznámky MOS, k provedení rychlého rozdělení oddílu na tomto prázdném oddílu se musím ujistit, že mám statistiky na prázdném oddílu.
Potvrdil jsem, že NUM_ROWS bylo 0 pro tento prázdný oddíl. Takže jsem nemusel počítat statistiky na oddílu. Moje první operace SPLIT PARTITION byla velmi rychlá, jen pár sekund. Oddíl byl prázdný a Oracle to věděl. Překvapilo mě, že nový oddíl, USAGE_TRACKING_P201601 a USAGE_TRACKING_PMAX přešel na hodnoty NULL pro statistiky. To znamenalo, že provedení operace SPLIT PARTITION pro druhý nový oddíl bude trvat dlouho. Zde je příklad toho, co mám na mysli. Nejprve vidíme 0 řádků v oddílu maximální hodnoty.
SQL> select num_rows from dba_tab_partitions
2 where partition_name='USAGE_TRACKING_PMAX';
NUM_ROWS
----------
0
Nyní ten oddíl rozdělím.
SQL> ALTER TABLE usage_tracking
2 SPLIT PARTITION usage_tracking_pmax AT ( TO_DATE('02/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') )
3 INTO (PARTITION usage_tracking_p201601, PARTITION usage_tracking_pmax);
Table altered.
Elapsed: 00:00:03.13
Všimněte si, že poslední dva oddíly nyní nemají žádné statistiky.
SQL> select num_rows from dba_tab_partitions
2 where partition_name='USAGE_TRACKING_PMAX';
NUM_ROWS
----------
SQL> select num_rows from dba_tab_partitions
2 where partition_name='USAGE_TRACKING_P201601';
NUM_ROWS
----------
Bez statistik trvá vytvoření dalšího rozděleného oddílu k vytvoření oddílu z února 2016 dlouho.
SQL> ALTER TABLE nau_system.usage_tracking
2 SPLIT PARTITION usage_tracking_pmax AT (TO_DATE('03/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS'))
3 INTO (PARTITION usage_tracking_p201602, PARTITION usage_tracking_pmax);
Table altered.
Elapsed: 00:27:41.09
Jak říká poznámka MOS, potřebujeme statistiky na oddílu, abychom mohli provést operaci rychlého rozdělení. Řešením je vypočítat statistiky oddílu a poté použít jeden příkaz ALTER TABLE k vytvoření všech oddílů najednou.
BEGIN
DBMS_STATS.gather_table_stats (tabname=>'USAGE_TRACKING',
partname => 'USAGE_TRACKING_PMAX',
granularity => 'PARTITION');
END;
/
ALTER TABLE usage_tracking
SPLIT PARTITION usage_tracking_pmax INTO
(PARTITION usage_tracking_p201601 VALUES LESS THAN (TO_DATE('02/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201602 VALUES LESS THAN (TO_DATE('03/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201603 VALUES LESS THAN (TO_DATE('04/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201604 VALUES LESS THAN (TO_DATE('05/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201605 VALUES LESS THAN (TO_DATE('06/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201606 VALUES LESS THAN (TO_DATE('07/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201607 VALUES LESS THAN (TO_DATE('08/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201608 VALUES LESS THAN (TO_DATE('09/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS')),
PARTITION usage_tracking_p201609 VALUES LESS THAN (TO_DATE('10/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
PARTITION usage_tracking_p201610 VALUES LESS THAN (TO_DATE('11/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
PARTITION usage_tracking_p201611 VALUES LESS THAN (TO_DATE('12/01/2016 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
PARTITION usage_tracking_p201612 VALUES LESS THAN (TO_DATE('01/01/2017 00:00:00','MM/DD/YYYY HH24:MI:SS') ),
PARTITION usage_tracking_pmax);
Pokud bych nechal skript provádět 12 jednotlivých operací SPLIT PARTITION, pak bych musel mezi každou z nich přepočítat statistiky o maximálním oddílu. Použití jednoho příkazu bylo efektivnější.