MySQL VS Oracle XE

Oracle XE vs MySQL
G.Morreale

Introduzione:

Dopo aver installato e provato(vedi precedenti articoli) la versione Express di Oracle è arrivato il momento di vedere se le prestazioni sono migliori o meno rispetto al noto dbms MySQL.

Scenario

Allora recupero la mia solita applicazione Java EE di test, costituita da un modulo EJB e un modulo WEB.
Il modulo EJB dotato di un session bean e un entity bean.

L'entity bean mappa la tabella esempiotable costituita da due colonne (id (INTEGER AUTOINC.), testo(STRING)).
Il persistence provider utilizzato è hibernate.
L'entitymanager utilizzato è un JTA Entity Manager ottenuto tramite dependency injection.
Il modulo Web è dotato di una servlet che ha il compito di richiamare il session bean presente nel modulo EJB.

Il test è una comparazione delle performance sia per quanto riguarda le operazioni di inserimento sul db che per ciò che concerne l'estrazione dei dati(SELECT).

Quindi il session bean(e relativa interfaccia locale) è dotato di due metodi:

  • Uno per l'inserimento di 'n' entityBean

    public void batchInsert(int nRows)
    {
        for (int i = 0; i < nRows; i++)
        {
            em.persist(new Esempiotable());            
        }
    }

  • l'altro per l'estrazione di tutti gli entityBean corrispondenti a tutte le righe della tabella di test

    public void listAll()
    {                
        List<Esempiotable> list = em.createNamedQuery("Esempiotable.ALL").getResultList();
        for (Esempiotable t: list)
        { System.out.println(t.getId());}        
    }


L'ambiente di sviluppo utilizzato è netbeans 6.1 dal quale sfrutterò il profiler per raccogliere i risultati ottenuti.
L'application server utilizzato è Glassfish V2.

Driver JDBC Mysql: mysql-connector-java-5.1.6-bin.jar
Driver JDBC Oracle:ojdbc14.jar

In Mysql storage engine utilizzato: "Inno DB"

L'Entity Bean

L'entity bean come già accennato è il mapping di una semplice tabella dotata di una colonna integer autoincrement e una colonna di testo.
Per cui il codice (valido per il mapping nei confronti di mysql) è:


@Entity
@Table(name = "esempiotable")
@NamedQueries(
{
   @NamedQuery(name = "Esempiotable.ALL", query = "SELECT e FROM Esempiotable e")
})
public class Esempiotable implements Serializable {
    private static final long serialVersionUID = 1L;
        
    @Id   
    @GeneratedValue(strategy=GenerationType.IDENTITY)    
    @Column(name = "id", nullable = false)
    private Integer id;
    
    @Column(name = "testo", nullable = true)
    private String testo;
//...omessi metodi accessor e costruttore


Tale mapping funziona correttamente su MySQL, ma utilizzandolo con Oracle si ottiene il seguente errore:

...
Caused by: java.lang.IllegalArgumentException: Dialect does not support identity key generation
        at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:223)
        at com.sun.enterprise.util.EntityManagerWrapper.persist(EntityManagerWrapper.java:440)
...

Ciò è dovuto al fatto che l'autoincrement di Oracle è gestito attraverso le sequenze, ovvero oggetti del db che indicano l'algoritmo di generazione e incremento della chiave primaria.
Quindi  "GenerationType.IDENTITY" deve essere sostituito con "GenerationType.SEQUENCE"

Tale modifica non è sufficente infatti si ottiene il seguente errore:

Caused by: javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not get next sequence value

L'errore si verifica perchè hibernate non è stato istruito circa quale sequence utilizzare.
Quindi attraverso SQLDeveloper andiamo a leggere il nome del sequence generator e indichiamolo attraverso le opportune annotation:

In definitiva il codice

@GeneratedValue(strategy=GenerationType.IDENTITY)  

Verrà sostituito con il seguente nel momento in cui il test dovrà essere eseguito su dbms oracle xe.

@GeneratedValue(strategy=GenerationType.AUTO, generator="ESEMPIOTABLE_ID_SEQ")
@SequenceGenerator(name="ESEMPIOTABLE_ID_SEQ", sequenceName="ESEMPIOTABLE_ID_SEQ")    

nota: E' stato utilizzato il metodo AUTO piuttosto che SEQUENCE per maggiore portabilità rispetto a futuri cambiamenti.


Gli Inserimenti

(Per la lettura dei risultati leggere il selftime dei metodi batchInsert o listAll)

Il primo test prevede un inserimento di 100.000 entity all'interno del db:
Vediamo subito i risultati:

Oracle XE


MySQL
Ripetiamo il test con 500.000

Oracle XE

MySQL

L'estrazione
Analizziamo i risultati di estrazione di 500.000 elementi:
Oracle XE
MySQL

Conclusione

Questi test sono da prendere con le pinze in quanto l'architettura del sistema dbms, application server, sistema operativo e quant'altro non è quella relativa a un sistema in "produzione".

Il setup e il tuning dei due dbms è quello standard, ovvero non è stata apportata alcuna modifica dopo l'installazione alla configurazione dei relativi dbms.

Inoltre i test sono relativi solo a 2 case e non prevedendo altri scenari tipici di un applicazione.

Fatte queste premesse, possiamo dire che mysql sia in fase di inserimento che in fase di estrazione ha dato dei risultati nettamente migliori.

Personalmente questi risultati nonostante siano basati su delle prove concrete mi lasciano un pò perplesso, in quanto mi aspetto di più lato Oracle. Se qualcuno che conosce bene Oracle XE può darci qualche consiglio per rifare i test in virtù di alcuni settaggi o accorgimenti ben venga.


No comments: