Domanda

Ecco la mia domanda:

select word_id, count(sentence_id) 
from sentence_word 
group by word_id 
having count(sentence_id) > 100;

La fraseword della tabella contiene 3 campi, wordid, fraseid e un ID chiave primaria. Ha 350k + righe. Questa query richiede ben 85 secondi e mi chiedo (sperando, pregando?) Che ci sia un modo più veloce per trovare tutti i wordid che hanno più di 100 fraseids.

Ho provato a togliere la parte di conteggio selezionata, e ho semplicemente fatto 'avere il conteggio (1)', ma nessuno dei due accelera.

Gradirei qualsiasi aiuto tu possa prestare. Grazie!

È stato utile?

Soluzione

  

avendo count (frase_id) > 100;

C'è un problema con questo ... O la tabella ha coppie duplicate di parole / frasi, oppure no.

Se ha coppie duplicate di parole / frasi, dovresti usare questo codice per ottenere la risposta corretta:

HAVING COUNT(DISTINCT Sentence_ID) > 100

Se la tabella non ha coppie duplicate di parole / frasi ... allora non dovresti contare frase_ids, devi solo contare le righe.

HAVING COUNT(*) > 100

In tal caso, puoi creare un indice su solo word_id , per prestazioni ottimali.

Altri suggerimenti

Se non ne hai già uno, crea un indice composito su frase_id, word_id.

Se la query viene spesso eseguita e la tabella viene aggiornata raramente, è possibile mantenere una tabella ausiliaria con ID di parole e conteggi delle frasi corrispondenti - difficile pensare a qualsiasi ulteriore ottimizzazione oltre a quella!

La tua query va bene, ma ha bisogno di un po 'di aiuto (indici) per ottenere risultati più veloci.

Non ho le mie risorse a portata di mano (o l'accesso a SQL), ma cercherò di aiutarti dalla memoria.

Concettualmente, l'unico modo per rispondere a quella query è contare tutti i record che condividono lo stesso word_id. Ciò significa che il motore di query ha bisogno di un modo rapido per trovare quei record. Senza un indice su word_id, l'unica cosa che il database può fare è passare attraverso la tabella un record alla volta e continuare a eseguire i totali di ogni singolo word_id distinto che trova. Ciò richiederebbe in genere una tabella temporanea e non è possibile inviare risultati fino alla scansione dell'intera tabella. Non va bene.

Con un indice su word_id, deve ancora passare attraverso la tabella, quindi penseresti non sarebbe di grande aiuto. Tuttavia, il motore SQL ora può calcolare il conteggio per ogni word_id senza attendere fino alla fine della tabella: può inviare la riga e il conteggio per quel valore di word_id (se passa la clausola where ) oppure scarta la riga (se non lo fa); ciò comporterà un minor carico di memoria sul server, possibilmente risposte parziali, e la tabella temporanea non è più necessaria. Un secondo aspetto è il parallelismo; con un indice su word_id, SQL può dividere il lavoro in blocchi e utilizzare core del processore separati per eseguire la query in parallelo (a seconda delle capacità hardware e del carico di lavoro esistente).

Potrebbe essere sufficiente per aiutare la tua query; ma dovrai provare a vedere:

CREATE INDEX someindexname ON sentence_word (word_id)

(sintassi T-SQL; non hai specificato quale prodotto SQL stai utilizzando)

Se questo non è abbastanza (o non aiuta affatto), ci sono altre due soluzioni.

Innanzitutto, SQL consente di precomputare COUNT (*) utilizzando viste indicizzate e altri meccanismi. Non ho i dettagli a portata di mano (e non lo faccio spesso). Se i tuoi dati non cambiano spesso, ciò ti darebbe risultati più rapidi ma con un costo in complessità e un po 'di spazio di archiviazione.

Inoltre, potresti considerare di memorizzare i risultati della query in una tabella separata. Questo è pratico solo se i dati non cambiano mai, o cambiano secondo una pianificazione precisa (diciamo, durante un aggiornamento dei dati alle 2 del mattino), o se cambiano molto poco e puoi vivere con risultati non perfetti per alcune ore (tu dovrebbe programmare un aggiornamento periodico dei dati); questo è l'equivalente morale del data warehouse di un uomo povero.

Il modo migliore per scoprire con certezza cosa funziona per te è eseguire la query e guardare il piano di query con e senza alcuni indici candidati come quello sopra.

Esiste, sorprendentemente, un modo ancora più veloce per farlo su grandi set di dati:

SELECT totals.word_id, totals.num 
  FROM (SELECT word_id, COUNT(*) AS num FROM sentence_word GROUP BY word_id) AS totals
 WHERE num > 1000;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top