2011-11-23 10 views
6

In Oracle ho una tabella partizionata. Le partizioni sono di dimensioni diverse e hanno una diversa distribuzione dei dati.C'è un modo per far sì che Hibernate usi i valori letterali piuttosto che le variabili di bind?

Mi piacerebbe avere un problema di ibernazione istruzioni SQL che include un valore letterale per la colonna chiave di partizione piuttosto che una variabile di binding. Dovrebbe utilizzare le variabili di binding per qualsiasi altro valore, naturalmente.

L'utilizzo di un valore letterale per la chiave di partizione consentirà a Oracle di elaborare un piano specifico per la partizione conosciuta e le statistiche raccolte. Questo potrebbe anche essere utile per le colonne che hanno un istogramma in atto per i dati inclinati.

Sarebbe preferibile specificarlo nell'entità altrimenti dovremo farlo in ogni query. C'è un modo per farlo in letargo?

Siamo in ibernazione 3.6.1 utilizzando Oracle 10g Dialect.

Se non c'è un modo per farlo in modo nativo in Hibernate, posso creare un tipo di utente o un dialetto o qualcosa per farlo accadere?

+1

La condivisione adattiva del cursore di 11g risolve i problemi? –

+0

@jonearles Sì, forse 11g risolverà questi problemi tramite la condivisione adattiva del cursore e/o il feedback della cardinalità. Stiamo lavorando per ottenere 11g fino alla produzione, ma ci sono test considerevoli da fare lì. –

+0

Per essere chiari, stai dicendo che l'eliminazione delle partizioni funziona con le variabili di binding, ma il piano di query all'interno della partizione (ad esempio, strategia di join) non lo fa? – wrschneider

risposta

1

No, i valori letterali non sono supportati in Sospensione. Dubito che tu possa fare una soluzione ma immagino tu stia cercando un'altra soluzione.

+2

Se non c'è assolutamente modo di farlo in Hibernate, non useremo la modalità di ibernazione. –

0

Come soluzione alternativa, è possibile impostare un commento univoco in ogni sito di chiamata "interessante", in modo da poter controllare la sbirciata della variabile di bind Oracle.

... 
query = session.createQuery("..."); 
... 
query.setString("param1", "FOO"); 
query.setInteger("param2", param2Value); 
... 
query.setComment("param1 = \"FOO\""); 
... 

In questo modo, l'ottimizzatore vedrà "FOO" in fase di analisi disco (come al solito). Nelle future chiamate, Oracle cercherà una copia esatta dell'SQL per riutilizzare il piano di esecuzione. Poiché il commento rende la query effettivamente unica, questo ti darà lo stesso piano di esecuzione calcolato con "FOO" e non qualsiasi altro valore di param1.

È necessario fare attenzione perché l'ottimizzatore utilizzerà anche il valore di param2Value per calcolare il piano di esecuzione, in modo che possa interferire. Ma penso che almeno valga la pena provare.

+1

Abbiamo disabilitato il bip della variabile di binding a causa dell'instabilità del piano che ha introdotto.Un esempio era un lavoro notturno in batch: qualsiasi istanza del cliente prima stabiliva il piano per quelli che seguivano. Questo non è sempre stato buono. –

+0

Bene, questo è il punto centrale di questa soluzione alternativa: le query che dovrebbero utilizzare piani diversi ottengono testo SQL differente, quindi non è necessario disabilitare la sbirciatina e perdere i suoi vantaggi. Ma bene, non hai intenzione di riattivarlo per questo. – gpeche

+0

Hai mai pensato di utilizzare i profili SQL per le query che potrebbero trarre vantaggio dal valore letterale? – gpeche

1

È possibile utilizzare il nomeNativeQuery qui è un'implementazione di esempio.

classe Entity è

@Entity 
@Table(catalog = DBCatalog) 
@org.hibernate.annotations.NamedNativeQuery(name="partitionTR1",query ="SELECT * FROM DATAMARTTRANSACTIONHISTORY PARTITION (tr1) where id=?",resultClass=DataMartTable.class) 
public class DataMartTransactionHistory implements TransactionHistory { 
    @Id 
    @Column 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private Long id; 
    @Enumerated(EnumType.ORDINAL) 
    private TransactionStatus transactionStatus; 
... other props... 
} 

ed ecco un implementazione dao.

public DataMartTransactionHistory findDataMartTransactionHistoryTR1(Long id) { 
    Query namedQuery = getSessionFactory().getCurrentSession().getNamedQuery("partitionTR1"); 
    namedQuery.setLong(0, id); 
    return (DataMartTransactionHistory)namedQuery.list().get(0); 
} 
+0

dal modo in cui il mio tavolo è come seguito. CREATE TABLE DATAMARTTRANSACTIONHISTORY ( NUMERO ID (19) NOT NULL, .... TRANSACTIONSTATUS NUMERO (10) ) PARTITION BY LIST (TRANSACTIONSTATUS) (valori TR1 partizioni (1), i valori di partizione TR2 (2)) – dursun

+0

Nella tua query denominata hai "where id =?". Stai dicendo che questo sarà sostituito con un valore letterale piuttosto che una variabile bind? –

+0

no è una variabile bind Ho aggiunto "PARTITION (tr1)" come letterale. puoi aggiungere altro qui. se me ne dai un esempio specifico, posso generarti un esempio specifico. – dursun