2009-08-07 4 views
5

Ho una tabella di grandi dimensioni (TokenFrequency) che contiene milioni di righe. La tabella TokenFrequency che è strutturato in questo modo:SQL Alternativa all'esecuzione di un INNER JOIN su una singola tabella

Tabella - TokenFrequency

  • id - int, chiave primaria
  • fonte - int, estera chiave
  • gettone - char
  • conteggio - int

Il mio obiettivo è selezionare tutte le righe in cui due sorgenti hanno lo stesso token. Per esempio, se la mia tabella si presentava così:

id --- --- fonte di token --- contare
1 ------ 1 --------- dog - ----- 1
2 ------ 2 --------- cat -------- 2
3 ------ 3 ----- ---- cat -------- 2
4 ------ 4 --------- pig -------- 5
5 ---- - 5 --------- zoo ------- 1
6 ------ 5 --------- gatto -------- 1
7 ------ 5 --------- maiale -------- 1

Vorrei una query SQL per darmi l'origine 1, l'origine 2 e la somma dei conteggi. Ad esempio:

sorgente1 --- sorgente2 --- gettone --- contare
---- 2 ----------- 3 --------- gatto -------- 4
---- 2 ----------- 5 --------- gatto -------- 3
---- 3 ----------- 5 --------- cat -------- 3
---- 4 ------- ---- 5 --------- -------- maiale 6

ho una domanda che assomiglia a questo:

SELECT F.source AS source1, S.source AS source2, F.token, 
     (F.count + S.count) AS sum 
FROM  TokenFrequency F 
INNER JOIN TokenFrequency S ON F.token = S.token 
WHERE F.source <> S.source 

Questa query funziona bene, ma i problemi che ho con esso sono che:

  1. Ho una tabella TokenFrequency che ha milioni di righe e quindi hanno bisogno di un alternativa più veloce per ottenere questo risultato.
  2. La query corrente che ho sta dando dei duplicati. Per esempio la sua selezione:
    source1 = 2, sorgente2 = 3, di token = gatto, count = 4
    source1 = 3, sorgente2 = 2, del token = gatto, count = 4
    che non è troppo di un problema ma se c'è un modo per elitarli e ottenere un aumento di velocità allora sarebbe molto utile

Il problema principale che ho è la velocità della query con la mia query corrente ci vogliono ore per completare. L'INNER JOIN su un tavolo è quello che ritengo essere il problema. Sono sicuro che ci deve essere un modo per eliminare il join interno e ottenere risultati simili usando solo un'istanza della tabella TokenFrequency. Il secondo problema che ho menzionato potrebbe anche promuovere un aumento di velocità nella query.

Ho bisogno di un modo per ristrutturare questa query per fornire gli stessi risultati in modo più rapido ed efficiente.

Grazie.

+1

È possibile pubblicare la DOMANDA della query (http://dev.mysql.com/doc/refman/5.0/en/explain.html). Aiuterà la gente a vedere come possono aiutarti a ottimizzare. –

+0

è necessario fornire alcune informazioni sull'indice, quali colonne, ecc. –

+0

Ecco la mia ESPLINA della query che ho inizialmente pubblicato. id: 1, select_type: SEMPLICE, tabella: F & S, tipo: ALL, Possible_keys: NULL, Chiave: NULL, Key_len: NULL, ref: NULL, righe: 8, Extra: Utilizzo di dove; Utilizzo del buffer di join Ci sono due righe restituite l'unica differenza sono i due nomi di tabella F e S. – cruzja

risposta

2

ci vorrebbe un po 'più di informazioni per diagnosticare il problema di velocità, ma per rimuovere il dups, aggiungi a al DOVE:

AND F.source<S.source 
+0

Ah così semplice. Questo ha funzionato perfettamente per eliminare i duplicati. Grazie – cruzja

2

Prova questo:

SELECT token, GROUP_CONCAT(source), SUM(count) 
FROM TokenFrequency 
GROUP BY token; 

Questo dovrebbe funzionare molto più veloce ed elimina anche i duplicati. Ma i sorgenti verranno restituiti in un elenco separato da virgole, quindi dovrai esploderlo nella tua applicazione.

Si potrebbe anche provare a creare un indice composto sulle colonne token, source, count (in questo ordine) e analizzare con EXPLAIN per vedere se MySQL è abbastanza intelligente per usarlo come covering index per questa query.


aggiornamento: Mi sembra di avere capito male la domanda. Non vuoi la somma dei conteggi per gettone, vuoi la somma dei conteggi per ogni coppia di fonti per un determinato token.

Credo che l'unione interna sia la soluzione migliore per questo. Un'importante linea guida per SQL è che se hai bisogno di calcolare un'espressione rispetto a due file differenti, allora devi fare un join.

Tuttavia, una tecnica di ottimizzazione che ho menzionato sopra è quella di utilizzare un indice di copertura in modo che tutte le colonne necessarie siano incluse in una struttura di dati dell'indice. Il vantaggio è che tutte le tue ricerche sono O (log n), e la query non ha bisogno di eseguire un secondo I/O per leggere la riga fisica per ottenere altre colonne.

In questo caso, è necessario creare l'indice di copertura sulle colonne token, source, count come sopra menzionato. Prova anche a allocare abbastanza spazio nella cache in modo che l'indice possa essere memorizzato nella cache.

+1

+1 per l'approccio giusto; ma un tale indice sarebbe grande quasi quanto l'intero disco, pensi che sarebbe più veloce della semplice indicizzazione su token? – Javier

+0

Dipende dal numero di righe e da altri fattori specifici del sistema. L'unico modo per essere sicuri è provarlo con * your * database e misurare le prestazioni. –

+0

Questo è un buon approccio, ma l'unico problema che si crea se si dispone di un token che si trova in più di una fonte, si ottengono tutti questi casi sommati.Per esempio nel mio caso di esempio il token "cat" è nei sorgenti 2,3 e 5 quindi quindi mi dà un conteggio di 5 invece di darmi 2 e 3 con conteggio di 4, 3 e 5 con un conteggio di 3, e 2 e 5 con un conteggio di 3. Nel mio vero e grande insieme di dati ci sono token che appaiono in quasi tutti i documenti che mi daranno GROUP_CONCAT di migliaia di fonti e il loro rispetto è importante. – cruzja

1

Se il token non è indicizzato, certamente dovrebbe essere.