venerdì 1 aprile 2016

RDBMS ORACLE - Partition Range By Interval - parte 2

Continuiamo con un esempio di quanto indicato nella parte 1 e due possibili soluzioni.

CREATE TABLE "ICP_ECONOMICO" 
   (
"PERIOD" NUMBER
   ) 
  PARTITION BY RANGE ("PERIOD") INTERVAL (1) 
 (PARTITION "P_0"  VALUES LESS THAN (196905) ) ;

Creato table "ICP_ECONOMICO".


set lines 300
col interval for a30
col TABLE_NAME for a30

select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='ICP_ECONOMICO'
order by table_name;

TABLE_NAME  PARTITION STATUS   INTERVAL  PARTITION_COUNT REAL_COUNT
----------- --------- -------- --------- --------------- ----------
ICP_ECONOMICO  RANGE     VALID    1          1048575          1

A questo punto inseriamo un record.

insert into ICP_ECONOMICO (period) values(20160101);

Errore con inizio alla riga : 178 nel comando -
insert into ICP_ECONOMICO (period) values(20160101)
Report error -
Errore SQL: ORA-14300: la chiave di partizionamento è mappata a una partizione non inclusa nel numero massimo consentito di partizioni
14300. 00000 -  "partitioning key maps to a partition outside maximum permitted number of partitions"
*Cause:    The row inserted had a partitioning key that maps to a partition number greater than 1048575
           *Action  Ensure that the partitioning key falls within 1048575 partitions or subpartitions.

Come si vede abbiamo l'errore che dicevamo, adesso se portiamo da 1 a 100 il by interval vediamo cosa accade:

ALTER TABLE ICP_ECONOMICO  SET INTERVAL (100);
Table ICP_ECONOMICO modificato.

Inseriamo una riga come prima.

insert into ICP_ECONOMICO (period) values(20160101);
1 riga inserito.

A questo punto se rifacciamo la query di sopra abbiamo:

set lines 300
col interval for a30
col TABLE_NAME for a30

select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='ICP_ECONOMICO'
order by table_name;

TABLE_NAME     PARTITION STATUS   INTERVAL  PARTITION_COUNT REAL_COUNT
-------------- --------- -------- --------- --------------- -----------------------------
ICP_ECONOMICO     RANGE     VALID    100           1048575          2


Se proviamo ad inserire altri record il problema non sembra più presentarsi a meno che non inserisce un valore che abbia un numero di cifre maggiore ad 8.

insert into ICP_ECONOMICO (period) values(99991201);
1 riga inserito.

insert into ICP_ECONOMICO (period) values(999912010);

Report error -
Errore SQL: ORA-14300: la chiave di partizionamento è mappata a una partizione non inclusa nel numero massimo consentito di partizioni
14300. 00000 -  "partitioning key maps to a partition outside maximum permitted number of partitions"
*Cause:    The row inserted had a partitioning key that maps to a partition number greater than 1048575
           *Action  Ensure that the partitioning key falls within 1048575 partitions or subpartitions.

A questo punto se modifichiamo nuovamente il valore dell'intervallo

ALTER TABLE ICP_ECONOMICO  SET INTERVAL (1000);
Table ICP_ECONOMICO modificato.
           
           
set lines 300
col interval for a30
col TABLE_NAME for a30

select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='ICP_ECONOMICO'
order by table_name;  


TABLE_NAME     PARTITION STATUS   INTERVAL  PARTITION_COUNT   REAL_COUNT
-------------- --------- -------- --------  ----------------- ----------
ICP_ECONOMICO     RANGE     VALID    1000     1048575          3


insert into ICP_ECONOMICO (period) values(999912010);
1 riga inserito.

A questo punto sembra che il  numero di cifre sia legato al valore dell'intervallo di partizionamento e più precisamente:

Intervallo 1        = Numero di cifre 6
Intervallo 100    = Numero di cifre 8
Intervallo 1000  = Numero di cifre 9

se inserisco adesso un numero di cifre pari a 10 avrò nuovemente l'errore.

insert into ICP_ECONOMICO (period) values(9999120101);

Report error -
Errore SQL: ORA-14300: la chiave di partizionamento è mappata a una partizione non inclusa nel numero massimo consentito di partizioni
14300. 00000 -  "partitioning key maps to a partition outside maximum permitted number of partitions"
*Cause:    The row inserted had a partitioning key that maps to a partition number greater than 1048575
           *Action  Ensure that the partitioning key falls within 1048575 partitions or subpartitions

 E qui vi lascio perchè non so dare alcuna spiegazione a questo comportamento.







RDBMS ORACLE - Partition Range By Interval - parte 1


Salve oggi brevemente vi parlo di un paio di bug di oracle, che sono una gran rottura di BIP e sono legati al partizionamento di una tabella by interval su un campo numerico e by interval su campo data.
Inoltre se si aggiunge al primo partizionamento anche un sottopartizionamento by hash che supera le 4 partizioni siamo al top.

Uno si può chiedere perchè utilizzare questo tipo di partizionamento e la risposta come al solito è dentro di voi ed è pure sbagliata. No a parte le cazzate il perchè p molto semplice le partizioni si autocreano e non c'è bisogno di un software che le crei, questo fa si che la gestione viene demandata completamente al database, purtroppo con le conseguenze indicate sotto.
Purtroppo non ho molto tempo per spiegarvi il problema vi rimando alle note che affrontano nel dettaglio i bugs.

  • Document  1507993.1 ORA-1841 on Select from Interval Partitioned Table when Predicate is 31-Dec-9999
  • Document 1479115.1 Interval Partitioning Essentials - Common Questions - Top Issues Document 1447928.1 PARTITION_COUNT Shows Large Value 1048575 With Interval Partitioning
  • Document 754642.1 How the PSTART/PSTOP Numbers are computed when a Interval Partition is used
  • Document 1472941.1 Insert Fails With ORA-14300 On Partition Table  
Per quanto riguarda la prima nota esiste un workaround che è quello di non far partire la data dal 01 del mese ma di farla partire dal 17 del mese. Il bug in questo caso è legato alla trasformazione della data Juliana nel normale formato anno mese e giorno.
Il secondo bug invece è una emerita stronza.. ed è legato ad uno pseudo valore massimo di partizioni in oracle che però non ha alcuna attinenza col valore contenuto nel campo.
Per verificare quante siano le partizioni indicate sul sistema e quante ve ne siano realmente basta eseguire la seguente query:


set lines 300
col interval for a30
col TABLE_NAME for a30
select table_name, PARTITIONING_TYPE, STATUS, INTERVAL, PARTITION_COUNT,
(select count(*) from user_tab_partitions pts where pts.table_name = pt.table_name) real_count
from user_part_tables pt
where table_name ='MV_FACT_TDB'
order by table_name;

TABLE_NAME                     PARTITION STATUS   INTERVAL      PARTITION_COUNT        REAL_COUNT
------------------------------ --------- -------- ------------- ---------------------- ----------
MV_FACT_TDB                    RANGE     VALID    100                         1048575          2


Dove la tabella ha in realtà 2 partizioni sottopartizionate by hash 4-




Vi lascio alla lettura delle note e dei relativi workaround, appena ritrovo i test che avevo fatto vi integro questo scarno documento.