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:
| C1 | VSIZE(C1) | C2 | VSIZE(C2) | C3 | VSIZE(C3) | C4 | VSIZE(C4) | C5 | VSIZE(C5) | C6 | VSIZE(C6) | C7 | VSIZE(C7) |
| A | 1 | | | | | | | | | | | | |
| | | FF | 10 | | | | | | | | | | |
| A | 1 | GG | 10 | GG | 2 | 21-GEN-2002 00:36:03 | 7 | 43 | 2 | 43,24 | 3 | 43,24 | 3 |
| B | 1 | CC | 10 | CC | 2 | | | 555 | 3 | 555,55 | 4 | 555555555,55 | 7 |
|
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.