Traduzione e Integrazione delle Lezioni a cura di Sandro Gallo
Home OLAP Introduzione
Le directory principali di MySql sono: BUILD, client, Docs, strings, myisam, mysys, sql, vio.
- La directory client contiene il codice sorgente di diversi programmi client, tra cui mysql; ed è scritto in c/c++. In più contiene programmi per il testing di servizi, tipo threading e SSH. Tra i suoi file più noti ci sono: mysql.cpp, mysqladmin.c, mysqlshow.c
- La directory docs contiene la documentazione dettagliata su MySQL internals:caching, guide per lo sviluppo, documentazione sulle strutture dati, informazione sulla libreria DBUG, Full-text search internals, informazioni sugli algorimi implementati.
- La cartella strings contiene funzioni per la manipolazione di caratteri, libreria C customizzata per le funzioni sulle stringhe, versione assembler, codifica per i caratteri, strmake.c
- Myisam è uno degli storage engine presenti in MySql; gli altri sono heap, innodb, ndb, bdb. Contiene programmi per la manipolazione di file righe e chiavi, ma non colonne
- Mysys sta per MySql System Library: è la toolbox directory, ad esempio contiene routine per l'accesso ai file a basso livello, contiene 115 file .c; contiene inoltre l'implementazione di diversi algoritmi e strutture dati hash, query, sort e tree; contiene un set di caratteri proprio e ha un codice indipendente dalla piattaforma.
- Sql presenta parecchi programmi importanti:
- Server, cioè la funzione mysqld.c che si occupa di inizializzazione, settaggio opzioni, gestione connessione, gestione segnali, shutdown
- Parser, cioè quello che converte un comando in un insieme di istruzioni esplicite (sql_lex, sql_yacc, ect). Vi sono poi gli handler, quelli cioè che stabiliscono a quale engine riferirsi e formattano gli argomenti in modo appropriato.
- Optimizer, che manipola operatori, espressioni, funzioni d'accesso ai campi.
- Statement execution.
- Item execution.
- Storage engine interface code.
- Vio, virtual input/output layer. Creato per il supporto SSL, esteso per incudere diversi protocolli di I/O, tcp/ip, sharede memory. È scritto in C.
La comunicazione tra client e server avviene attraverso i seguenti passi:
- il client inserisce un comando (client)
- il messaggio è inviato al server (vio)
- il server fa il parsing del comando (sql)
- viene invocato il comando di esecuzione (sql_command.cc)
- l'handler recupera lo storage engine
- vengono eseguite le chiamate a basso livello
- viene eseguito il comando e i risultati sono inviati al client
Oltre alle directory già viste abbiamo quelle del sistema operativo e delle utility open source.
L'utente ha la possibilità di definire UDF native cioè funzioni native. Per fare ciò dovranno essere aggiunte alle funzioni di parsing, alle tabelle, ai comandi le righe corrispondenti alle nuove funzioni.
Lo stato attuale di MySql comprende per ogni categoria le suguenti funzionalità:
- Data Mining:
- Apriori
- Decision Trees
- Data Cleaning (ETL):
Table Integration
- Multidimensionalità (OLAP):
- Star Schema
- Operator CUBE
- Supporto I/O dedicato:
Nuovo Storage Engine: B+Tree con buffering.
Berkeley DB è un database ad alte prestazioni non relazionale per sviluppatori, più usato al mondo. Berkeley DB è realizzatto in forma di libreria, scritta in C. Alla libreria vengono aggiunte interfacce verso altri linguaggi, come:
- C/C++, Java, C#
- PHP, Perl, Ruby, Tcl.
È stato portato sulla maggior parte dei sistemi operativi, inclusi Linux, MacOs X, QNX, Unix, VxWroks, Windows.
La Oracle Berkeley DB Product Family comprende:
- Berkeley DB
- Berkeley DB Java Edition
- Berkeley DB XML Edition
Berkeley DB dà numerosi vantaggi:
- Codice sorgente open,
- massima configurabilità,
- semplici API per scrivere applicazini in C, C++, Java, Perl, Python, Tcl, PHP, C#,
- pieno supporto alle transazioni
- memoria richiesta molto piccola
- alte prestazioni
- zero costi di amministrazione, è invisibile agli utenti.
Le alte prestazioni sono dovute a:
- Il server è eseguito nello stesso processo dell'applicazione, senza il sovraccarico della comunicazione client/server.
- Offre solo API e non ci sono linguaggi query.
- Non usa tabelle, ma solo coppie chiave/dato.
Infatti i database sono organizzati in file. Ogni database è contenuto in un file (però un file può contenere molti database). Il database contiene i record organizzati in base al metodo di accesso scelto (albero, tabella hash, coda). Un record è composto da una chiave e da un dato. I dati possono essere delle strutture complesse come per esempio strutture di linguaggio C. Berkeley DB supporta le chiavi duplicate. Si può scegliere di leggere solo il primo record con la chiave specificata o l'insieme di tutti i record che hanno questa chiave.
I metodi put(chiave,dato) e get(chiave) servono a leggere e inserire i dati nel database.
C'è a disposizione un meccanismo speciale chiamato cursore. I cursori sono essenzialmente degli iteratori e servono per scorrere tutti i record nel database dal primo all’ultimo o viceversa. I cursori permettono di enumerare tutti i record che hanno la stessa chiave. I database secondari permettono di implementare gli indici secondari. Grazie a loro si può effettuare una ricerca nel database non solo usando le chiavi ma anche i dati.
Il Metodo di Accesso determina come vengono organizzate fisicamente le coppie chiave/dati nel file del database. La scelta del metodo di accesso dipende dal tipo dei dati e dalle operazioni effettuate. Possiamo scegliere tra:
- BTree – i dati sono organizzati in un albero ordinato e bilanciato. Si consiglia di scegliere questa struttura quando si suppone che esista una “località” di query in database, cioè, se viene letto un record, è molto probabile che vengano letti i suoi “vicini”.
- Hash – i dati sono organizzati in una tabella hash. Utile per database molto grandi o per accessi random.
- Queue e Renco – i dati vengano organizzati in una coda. Come chiavi si usano i numeri interi.
Le funzioni per aprire e chiudere un database sono illustrate di seguito:
#include // header della libreria
//Crea un oggetto del database
Db db(NULL,0);
db.open( NULL, //Transaction pointer
"mydb.db", //Il nome del file
NULL, //Il nome logico del database (opzionale)
DB_BTREE, //Il metodo di accesso
DB_CREATE, //Creare un nuovo database
0); //I permessi di accesso per il file (solo Linux)
int Db::open(DbTxn *txnid, const char *file, const char *database, DBTYPE type, u_int32_t flags, int mode);
I parametri sono i seguenti:
txnid – transaction pointer o NULL se le transazioni non servono.
file – il nome del file del database.
database - il nome logico del database è opzionale. Serve per avere tanti database nello stesso file.
type – il metodo di accesso: DB_BTREE, DB_HASH, DB_QUEUE or DB_RECNO.
flags – DB_CREATE (creare un nuovo database), DB_RDONLY (solo lettura), DB_TRUNCATE (cancellare tutti i database che si trovano nel file), DB_DUPSORT (ordinare le chiavi duplicate)
mode – permessi di accesso (solo per linux). 0 per la scelta degli accessi predefeniti.
Una volta finito il lavoro con il database, esso deve essere chiuso. Il metodo Db::close() svuota la cache, chiude tutti i cursori aperti, libera le risorse allocate, e chiude tutti i file aperti:
#include
...
Db db(NULL,0);
db.open(NULL,"mydb.db",NULL,DB_BTREE,DB_CREATE,0);
... // lavoro con il database
db.close(0); //chiudere il database
Alcune funzioni per amministrare il database sono:
- Restituire i flag di apertura:
u_int32_t open_flags;
db.get_open_flags(&open_flags);
- Cancellare un database:
db.remove("mydb.db", //Database file
NULL, //Il nome logico del database.
//Se NULL viene cancellato il file intero
0); //Settato sempre a zero--Non si usa.
- Rinominare un database:
db.rename("mydb.db", //Database file
NULL, //Database da rinominare. Se NULL
//viene rinominato il file stesso
"newdb.db", //Nuovo nome del database
0); //Non si usa.
Alcune funzioni per configurare il DataBase sono:
DB::set_error_stream(&cerr);
Assegnare un C++ ostream per la visualizzazione dei messaggi di errori in Berkeley DB.
Db::set_errpfx(“MyBDB: ");
Fissare un prefisso per tutti messaggi d'errore di Berkeley DB.
Db::set_pagesize(1024);
All'interno, il DB conserva i record nelle pagine. La dimensione delle pagine è molto importante perchè può influire sulle prestazioni dell'applicazione. La dimensione deve essere una potenza di 2.
Db::set_cachesize(0/*gigabytes*/, 32768/*bytes*/, 0);
Fissare la dimensione della cache di memoria condivisa.
Ogni record è composto da due oggetti Dbt : uno per la chiave e un altro per il dato. Il costruttore è
Dbt(void *data, size_t size);
Per inserire un record nel database si utilizza il metodo Db::put(chiave,dato). Questo metodo richiede la chiave e il dato in forma di oggetti Dbt. Si possono fornire uno o più flag che controllano il comportamento del DB durante l'inserimento. Per esempio il flag DB_NOOVERWRITE non permette di sovrascrivere un record già esistente nel database. La funzione è:
int Db::put(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
Per leggere i record da un database si utilizzano le seguenti funzioni:
Db::get(chiave) serve per leggere i record dal database
Db::get() torna il primo record che ha la chiave uguale alla chiave specificata.
Se la chiave specificata non esiste nel database, il metodo torna DB_NOTFOUND.
Per cancellare un record si usa la funzione:
Db::del() cancella tutti i record che hanno la chiave specificata
Se la chiave specificata non è presente nel database il metodo restituisce DB_NOTFOUND.
I cursori sono essenzialmente degli iteratori e servono per attraversare tutti i record nel database dal primo all'ultimo o viceversa. Sono anche l'unico modo per enumerare tutti i record che hanno la stessa chiave.
Dbc *cur; // Il cursor
Db db(NULL, 0); // Il database
… // db.open(…)
db.cursor(NULL, &cur, 0);
… // lavoro con il cursore
if (cur != NULL) cur->close();
db.close(0);
Per scorrere il database intero, dal primo all' ultimo record, basta creare un cursore e usare il suo metodo Dbc:get() con il flag DB_NEXT:
// Iterazione di tutto il database, prendendo un record per volta.
while ((ret = cursorp->get(&key, &data, DB_NEXT)) == 0)
{
… // elaborazione del record
}
Per scorrere il database dall'ultimo record al primo, specificare DB_PREV al posto del DB_NEXT.
Un record è un record duplicato se nel database si trova un altro record con la stessa chiave.
I seguenti flag del metodo Dbc::get() sono utili per lavorare con i record duplicati:
- DB_NEXT_NODUP, DB_PREV_NODUP – Legge il prossimo record non duplicato nel database.
- DB_NEXT_DUP - Legge il prossimo record che ha la stessa chiave.
- DB_SET – Sposta il cursore al primo record con la chiave specificata.
Per inserire un nuovo record nel database viene usato il metodo del cursore Dbc::put(), il quale è molto simile a Db::put() ma supporta anche i record duplicati. I flag importanti sono:
- DB_AFTER – inserire il record dopo la posizione corrente
- DB_BEFORE – inserire il record prima della posizione corrente
- DB_KEYFIRST – inserire il record come il primo del gruppo dei record che condividono la chiave specificata.
- DB_KEYLAST – inserire il record come l'ultimo del gruppo dei record che condividono la chiave specificata.
E' possibile specificare la funzione propria per il confronto dei record duplicati che Berkeley DB userà per l'ordinamento dei record che hanno la stessa chiave: db::set_dup_compare(…).
Per cancellare un record basta posizionare il cursore sul record stesso e chiamare il metodo Dbc:del(0):
cursorp->get(&key, &data, DB_SET);
cursorp->del(0);
Per sostituire un record basta chiamare il metodo Dbc::put() con il flag DB_CURRENT:
ret = cursorp->get(&key, &data, DB_SET);
if (ret == 0) {
data.set_data(replacement_data);
data.set_size(strlen(replacement_data) + 1);
cursorp->put(&key, &data, DB_CURRENT);
}
Di solito la ricerca sul database si effettua per chiave. Ma ci sono casi in cui occorre trovare i record che contengono dati specifici. Invece di scorrere il database intero, verificare uno per uno i record e controllare se contiene un venditore di Catania, si può creare un indice basato sulla porzione dei dati, in nostro caso sulla città. Questa operazione si può fare usando il database secondario. Nel database secondario i record sono composti dalla chiave, che costituisce un indice secondario per il database primario, e dai dati, che corrispondono alle chiavi del database primario.
La procedura per creare un database secondario è la seguente:
- Creare il database secondario.
- Aprire il database secondario.
- Collegare al database primario.
- Fornire una funzione callback, che crea la chiave secondaria dal record primario.
Berkeley Db aggiorna automaticamente il database secondario quando vengono aggiunti nuovi record (o cancellati record esistenti) nel database primario.
Db db(NULL, 0); // Il database normale
Db sdb(NULL, 0); // Il database secondario
db.open(NULL, "vendor.db", NULL,DB_BTREE, DB_RD_ONLY, 0);
// DB secondario può avere le chiavi duplicate
sdb.set_flags(DB_DUPSORT);
// Creazione del db secondario
sdb.open(NULL,"my_index.db", NULL, DB_BTREE, DB_CREATE, 0);
// colleghiamo i due database
db.associate(NULL, &sdb,
get_city, // Callback per estrazione della chiave secondaria.
0);
Si possono leggere i record dal database secondario usando i metodi Db::get() o Db::pget(), o usando il cursore del database secondario. Il metodo Db::get() restituisce la chiave dal database secondario e i dati dal database primario. Il metodo Db::pget() in più restituisce la chiave dal database primario.
Altre caratteristiche del Berkeley DB non trattate sono:
- Transazione ACID
- Replicazione
- Supporto Multi-thread (Mutex, Locking)
- Mutexes
- Management del pool di memoria
- Logging
- Funzione hash definita dall'utente
Berkeley DB XML è un database Xml Nativo. Berkeley DB XML fornisce un accesso tramite Xquery ad un contenitore di documenti xml. I documenti xml vengono salvati ed indicizzati in formato nativo usando Berkley DB ed il suo motore transazionale.
Le sue caratteristich e sono: supporta XQuery 1.0 July 2004 draft; supporta XPath 2.0; supporta XML Namespaces; sttimizzazione e precompilazione delle query; Transazioni, recovery automatico,data encryption, replicazione; Indicizza i nodi XML, gli elementi, attributi e anche i meta-dati.
Berkeley DB Java Edition è un database transazionale ad alta performance scritto interamente in Java .
Caratteristiche: le API forniscono interfacce Java Collection; salva i dati in formato nativo, salva oggetti Java; transazioni controllate tramite Java Transaction Api (JTA); possibilità di integrazione in un application server Java EE(J2EE) tramite le API Connector Architecture (JCA); Il controllo e l'audit tramite Java Management Extensions (JMX); supporto per processi singoli o multi-threaded.
Home OLAP Introduzione