- SQL
- PL/SQL
- DBA
- Developer / Forms
- Developer / Reports
- Developer / Graphics
- Data-Warehouse

 
 
 

 
> Tutorials DBA
 

Dimensionamento delle tabelle
di Giovanni Bronzini

Ogni istanza del database Oracle è strutturata in diversi files.
L'insieme minimo dei files per ogni istanza è il seguente:
· datafiles
· redo log
· control files
· init.ora


I datafiles contengono i dati memorizzati nel database.
Uno o più datafiles sono raggruppati nelle "tablespaces" che possiamo considerare come il punto di congiunzione tra la struttura logica e fisica della base dati.
La loro dimensione può essere fissa o possono essere configurati per "auto-estendersi" in caso di maggiore richiesta di spazio.

Ogni istanza di Oracle possiede un set di 2 o più "redo log files" il cui compito è quello di tracciare i cambiamenti che avvengono sui dati.
E' possibile utilizzare le informazioni memorizzate in questi files per effettuare operazioni di recovery o addirittura come fonte dati per un database di backup il quale si terrebbe sincronizzato con il primario semplicemente "leggendo" le modifiche nei redo logs del primario stesso (stand-by database).
I redo logs sono sovrascritti ciclicamente ma se il DB è in modalità ARCHIVELOG, prima di essere riscritti sono copiati in una directory definibile nell' init.ora. Le copie di questi files vengono chiamati "archived redo logs".

I Control files contengono informazioni sulla struttura fisica del db ed anche
il nome dell'istanza, i nomi e i path dei datafiles e dei redo logs.
Questo è il motivo per il quale i control files debbono comparire nell' init.ora, infatti all'avvio dell'engine contengono le ubicazioni degli altri files da aprire.
Per esempio:

control_files=("e:\ora9i\oradata\db\CONTROL01.CTL",
               "e:\ora9i\oradata\db\CONTROL02.CTL",
               "e:\ora9i\oradata\db\CONTROL03.CTL")

Il file init.ora è invece il file che, come abbiamo visto, contiene i parametri di inizializzazione dell'istanza.

Analizziamo ora in dettaglio la struttura dei datafiles.

Il livello di maggiore granularità, corrispondente al più piccolo blocco indirizzabile dal database, è rappresentato dai database blocks la cui dimensione è espressa dal parametro DB_BLOCK_SIZE.
Sebbene tale parametro sia presente nel file di inizializzazione dell'istanza [nomeSID]INI.ora non può essere modificato a meno di non ricreare l'istanza stessa.
DB_BLOCK_SIZE esprime la dimensione in bytes dell'unità minima di allocazione dello spazio (anche detta pagina) dell'istanza.
Il range di valori ammessi varia da 2Kb (2048bytes) a 32Kb (32768bytes) anche se tipicamente si utilizzano valori compresi tra i 2 e i 4 Kb.
Oracle consiglia comunque di far coincidere la dimensione del blocco con la dimensione del cluster. In ambiente UNIX si può utilizzare il seguente comando per conoscere la dimensione del cluster: "df -g"
In caso di utilizzo di Oracle Parallel Server ogni istanza deve avere il medesimo valore per tale parametro.

Ad un livello superiore troviamo le "extents" che non sono altro che un raggruppamento di blocchi contigui. Le extents sono l'unità minima di allocazione. Quando, ad esempio, una tabella viene creata, Oracle riserva per essa uno spazio contiguo pari alla dimensione specificata dalla clausola "initial" del comando di creazione della tabella o, in mancanza di esso, dal parametro "initial" della tablespace dove viene creato l'oggetto.
(Ricordiamo che le tablespace hanno i medesimi parametri di "STORAGE" utilizzati nella creazione delle tabelle. I valori di tali parametri vengono usati quando non sono esplicitati nel comando "CREATE TABLE")
Qualora fosse richiesto ulteriore spazio per memorizzare i dati, la dimensione allocata corrisponderà invece a quella definita nella clausola "next" o nel corrispettivo parametro della tablespace.
Segue un elenco delle "clausole di STORAGE" per le tabelle o per le tablespaces:

·initial - dimensione dell'extent iniziale
·next - dimensione della seconda extent
·pctincrease - percentuale di incremento delle dimensioni delle extents dalla terza in poi relativa all'extent precedente
·minextents - numero minimo di extents allocate
·maxextents - numero massimo di extents allocate
·optimal (utilizzabile solo per i segmenti di rollback)

Per fare un esempio, supponendo di avere una tabella creata con i seguenti parametri: initial=10K next=20K pctincrease=50 minextents=3 maxextents=unlimited
Tale tabella sara' creata con un segmento iniziale composto da 3 extents come specificato nella clausola minextents, e le dimensioni delle sue extents saranno le seguenti: 10K per la prima (vedi parametro initial), 20k per la seconda (vedi parametro next), 30K la terza (dimensioni della seconda incrementate del 50% : 20 * 1,5 = 30 ), 45K la quarta e così via...

Esempi di comandi:

CREATE TABLE Esempio
(
   campo1                         VARCHAR2(10)
)
TABLESPACE USERS
PCTFREE 11
PCTUSED 41
STORAGE (
   INITIAL 10 K
   NEXT 20 K
   MAXEXTENTS 81
  PCTINCREASE 44
 );

ALTER TABLE esempio2 STORAGE (NEXT 500K);

ALTER TABLE...ALLOCATE EXTENT

Viene invece chiamato "segment" un insieme di extents, tutti utilizzati per memorizzare lo stesso tipo di oggetto di database.

Esistono dunque 5 tipi di segments:
1) Table segments
 Utilizzati per memorizzare i dati del DB
2) Index segments
 Utilizzati per memorizzare gli indici delle tabelle
3) Rollback segments
 Utilizzati per memorizzare i dati modificati nel corso delle transazioni, consentono la "read-consistency" (finché una transazione non viene "committata" le altre sessioni non "vedono" le modifiche) e la "transaction concurrency" (ovvero la possibilità degli utenti di aprire diverse transazioni contemporaneamente)
4) Cluster segments
 Specifici per i cluster. I cluster sono un insieme di tabelle ("cluster" in inglese significa appunto "grappolo") che condividono un indice (detto "indice di cluster"), che permettono di ottimizzare queries che le coinvolgono (condividendo il medesimo indice le operazioni di join richiedono un minor accesso al disco).
5) Temporary segments
 Utilizzati per creare degli oggetti temporanei o aree di appoggio (ad esempio durante gli ordinamenti dei dati di una query).

Avendo caratteristiche così diverse tra loro è consigliabile separarli in diverse tablespaces per poter ottimizzare i loro parametri di allocazione.

Vediamo ora come procedere per il dimensionamento delle tabelle di un database.

La funzione VSIZE ritorna il numero di bytes utilizzati per la memorizzazione del dato.

SQL> desc DIMTEST
 Nome                                  Null?   Tipe
 --------------------------- -------- -----------------------
 C1                                                 CHAR(1)
 C2                                                 CHAR(10)
 C3                                                 VARCHAR2(10)
 C4                                                 DATE
 C5                                                 NUMBER(5)
 C6                                                 NUMBER(5,2)
 C7                                                 NUMBER


SELECT
    C1,vsize(c1),
    C2,vsize(c2),
    C3,vsize(c3),
    C4,vsize(c4),
    C5,vsize(c5),
    C6,vsize(c6),
    C7,vsize(c7)
 FROM SCOTT.DIMTEST

Il risultato sarà il seguente:

C1VSIZE(C1)C2VSIZE(C2)C3VSIZE(C3)C4VSIZE(C4)C5VSIZE(C5)C6VSIZE(C6)C7VSIZE(C7)
A1            
  FF 10          
A1GG 10GG221-GEN-2002 00:36:03743243,24343,243
B1CC 10CC2  5553555,554555555555,557

Per pianificare un corretto dimensionamento di una tabella occorre conoscere con buona approssimazione la dimensione media delle sue righe.
Applicando alla SELECT precedente la funzione avg() per ogni vsize() e aggiungendo il valore fisso 3 otteniamo la dimensione media della riga DMR.

DMR = 3 + avg(vsize(col1)) + avg(vsize(col2)) + . . . + avg(vsize(colN))

Ovviamente disponendo di un set di dati campione si può preocedere analizzando la tabella con il comando:

ANALYZE TABLE NomeTabella COMPUTE STATISTICS;

e interrogare il data-dictionary per ottenere direttamente la DMR:

SELECT AVG_ROW_LEN FROM USER_TABLES WHERE TABLE_NAME='NOMETABELLA';

Una prima stima X del numero di righe contenute in un blocco si può dunque ricavare dalla formula seguente:

X = DB_BLOCK_SIZE / DMR

Tuttavia oltre allo spazio occupato dai dati stessi, in un blocco dobbiamo considerare anche un parte fissa così definibile:
24 bytes sono fissi nell'intestazione
altri 24 * initrans servono per il "transaction header" dove "initrans" vale 1 per le tabelle e 2 per i cluster
4 bytes servono per la "table directory"
4 bytes servono per ogni riga nel blocco

Sia ora Y il numero di bytes disponibili per i dati in un blocco:

per le tabelle (e non per i cluster) Y = DB_BLOCK_SIZE - ( pctfree(DB_BLOCK_SIZE - (52 + 4X) ) )

Per trovare il corretto numero X occorre ora diminuire X finché non sia verificata la formula: Y >= X * DMR

Naturalmente il risultato ottenuto non sarà assolutamente affidabile a meno di un 1 o 2 % di margine di cui dovrete tener conto. Questo margine è dovuto all'impossibilità di ottenere un numero esatto per la DMR.

Nel caso degli indici vi sono alcune differenze:
Il valore di initrans e sempre 2.
L'header fisso è di 113 bytes invece che di 24.
L'header per ogni nodo (l'equivalente dell'header delle righe che nelle tabelle occupa 3 bytes) occupa soli 2 bytes.
Occorre sottrarre il numero di righe in cui i campi indicizzati sono NULL dal numero totale di nodi da allocare.
Ogni nodo occuperà mediamente quanto occupano in media le colonne coinvolte più un valore fisso corrispondente alla dimensione del campo ROWID ( da 6 a 10 bytes a seconda delle versioni di Oracle:
comunque ottenibile dal comonado "select vsize(rowid) from dual") più 2 bytes per l'header di nodo più un bytes per ogni colonna membro dell'indice.

Per il resto il procedimento può effettuarsi come già visto per le tabelle.

Naturalmente in caso di tipi di dato particolari come il LONG o nel caso del dimensionamento dei cluster la faccenda si complica e per questo sarà necessario un ulteriore approfondimento.
Nel frattempo spero che queste informazioni siano state utili a migliorare la vostra comprensione della struttura dei dati di Oracle Database Server.