2010-01-25 21 views
10

Ho un tavolo enorme con cui lavorare. Voglio verificare se ci sono alcuni record il cui parent_id è uguale al mio valore di passaggio. attualmente quello che implemento è usando "select count (*) da mytable dove parent_id =: id"; se il risultato> 0, significa che esistono.Il modo più veloce per verificare se alcuni record in una tabella di database?

Poiché si tratta di una tabella molto grande, e non mi interessa quale sia esattamente il numero di record esistenti, voglio solo sapere se esiste, quindi penso che count (*) sia un po 'inefficiente.

Come implementare questo requisito nel modo più rapido? Sto usando Oracle 10.

#

Secondo letargo Consigli & Tricks https://www.hibernate.org/118.html#A2

Si suggerisce di scrivere in questo modo:

Integer count = (Integer) session.createQuery ("select count (*) da .... "). uniqueResult();

Non so qual è la magia di uniqueResult() qui? perché lo rende veloce?

Confronta "seleziona 1 da mytable dove parent_id = passingId e rowrum < 2", che è più efficiente?

risposta

9

Un ESISTE interrogazione è quello di andare per se non siete interessati al numero di record:

select 'Y' from dual where exists (select 1 from mytable where parent_id = :id) 

Ciò restituirà 'Y' se esiste un record e niente altro.

[In termini di domanda su "uniqueResult" di Hibernate, tutto ciò che viene restituito è un singolo oggetto quando è presente un solo oggetto da restituire, anziché un set contenente 1 oggetto. . Se più risultati vengono restituiti il ​​metodo genera un'eccezione]

+0

Non hai nemmeno bisogno di interrogare DUAL - 'seleziona 'Y' da mytable dove parent_id =: id AND ROWNUM = 1' dà risultati identici. –

+0

Sì, semplicemente non mi piace "ROWNUM = 1" - non si sente trasparente come una query EXISTS. Solo io però. –

2

Prima di tutto, è necessario un indice su mytable.parent_id.

Ciò dovrebbe rendere la query abbastanza veloce, anche per le tabelle di grandi dimensioni (a meno che non ci siano anche molte righe con lo stesso parent_id).

In caso contrario, si potrebbe scrivere

select 1 from mytable where parent_id = :id and rownum < 2 

che restituire una singola riga contenente 1, o nessuna riga a tutti. Non ha bisogno di contare le righe, basta trovarne una e poi uscire. Ma questo è SQL specifico per Oracle (a causa del rownum), e non dovresti farlo.

+0

+1 per la raccomandazione indice –

+2

Vorrei andare per una query EXISTS Penso - più trasparente al requisito: selezionare 1 da doppio dove esiste (selezionare 1 da mytable dove parent_id =: id) –

0

Per DB2 c'è qualcosa come select * from mytable where parent_id = ? fetch first 1 row only. Suppongo che esista qualcosa di simile per Oracle.

+1

Tutti i dialetti SQl differiscono - non puoi supporre che ci siano cose simili, ad es Oracle ha rownum che non è presente in Sybase e penso in DB2 – Mark

+2

, quindi il concetto di rownum è quello che chiamerei "simile" perché copre lo stesso caso d'uso, ovvero i primi record n ​​(http: //www.petefreitag. it/item/59.cfm) – bertolami

+0

re: top n. Un problema con il rownum è che viene valutato prima che ogni ordinamento sia fatto, quindi non è veramente "top" n. – Thilo

4

Non c'è alcuna reale differenza tra:

select 'y' 
    from dual 
where exists (select 1 
       from child_table 
       where parent_key = :somevalue) 

e

select 'y' 
    from mytable 
where parent_key = :somevalue 
    and rownum = 1; 

... almeno in Oracle10gR2 e fino. Oracle è abbastanza intelligente in quella versione per eseguire un'operazione DUAL FAST in cui azzera qualsiasi attività reale contro di essa. La seconda query sarebbe più facile da eseguire se questa è sempre una considerazione.

Il vero differenziatore delle prestazioni è se la colonna parent_key è indicizzata o meno. Se non lo è, allora si dovrebbe eseguire qualcosa di simile:

select 'y' 
    from dual 
where exists (select 1 
       from parent_able 
       where parent_key = :somevalue) 
5

select count (*) dovrebbe essere lighteningly veloce se si dispone di un indice, e se non lo fai, permettendo il database di abortire dopo la prima partita vinta Aiuta molto.

Ma dal momento che lei ha chiesto:

boolean exists = session.createQuery("select parent_id from Entity where parent_id=?") 
         .setParameter(...) 
         .setMaxResults(1) 
         .uniqueResult() 
       != null; 

(alcuni errori di sintassi da aspettarselo, dal momento che non ho un'ibernazione da confrontare su questo computer)

Per Oracle, maxResults si traduce in rownum in ibernazione.

Per quanto riguarda uniqueResult(), leggere il relativo JavaDoc! L'utilizzo di uniqueResult anziché di list() non ha alcun impatto sulle prestazioni; se ricordo male, l'implementazione dei delegati uniqueResult da list().

+0

+1 per setMaxResults – Thilo

0

Questa query restituirà 1 se non esiste alcun record e 0 altrimenti:

SELECT COUNT(1) FROM (SELECT 1 FROM mytable WHERE ROWNUM < 2); 

Potrebbe aiutare quando è necessario controllare le statistiche dati della tabella, indipendentemente dimensioni tavolo e qualsiasi problema di prestazioni.

Problemi correlati