2010-11-15 10 views
5

Se si dispone di una ricerca del tipo:SQLite unire ottimizzazione

select a.Name, a.Description from a 
inner join b on a.id1 = b.id1 
inner join c on b.id2 = c.id2 
group by a.Name, a.Description 

Quali sarebbero le colonne più ottimali per indicizzare per questa query in SQLite se si considera che ci sono oltre 100.000 righe in ciascuna delle tabelle?

La ragione per cui chiedo è che non ottengo le prestazioni con la query con il gruppo da quella che mi aspetterei da un altro RDBMS (SQL Server) quando applico la stessa ottimizzazione.

Avrei ragione nel pensare che tutte le colonne referenziate su una singola tabella in una query in SQLite debbano essere incluse in un singolo indice composito per le migliori prestazioni?

+2

Il mio psicopatico interiore sta agitando il fatto che tu abbia un gruppo per clausola senza alcuna funzione aggregata. Cosa stai cercando di ottenere con il gruppo? –

+1

@MyOtherMe: vedere la mia risposta qui sotto, penso che voglia una distinta di tutte le descrizioni e nomi a cui si fa riferimento nelle tabelle bec. – MPelletier

+0

Questo è esattamente quello che sto cercando. – gmn

risposta

4

Il problema è che ci si aspetta che SQLite abbia le stesse caratteristiche di prestazioni di un RDBMS completo. Non lo farà. SQLLite non ha il lusso di arrivare alla cache abbastanza in memoria, deve ricostruire la cache ogni volta che si esegue l'applicazione, è probabilmente limitato a impostare il numero di core, ecc, ecc. Ecc. Compiti per l'utilizzo di un RDBMS incorporato su uno pieno.

Per quanto riguarda le ottimizzazioni, provare a indicizzare le colonne di ricerca e testare. Quindi prova a creare un indice di copertura. Assicurati di testare entrambi i percorsi selects e codice che aggiornano il database, ne stai accelerando uno a scapito dell'altro. Trova l'indicizzazione che offre il miglior equilibrio tra i due per le tue esigenze e vai con esso.

+0

Grazie per la risposta, in precedenza ho tentato di aggiungere un indice composito in precedenza su a.Id1, a.name, a.description e un composito su b.id1, ​​b.id2 e un altro indice su c.id2. Tuttavia, nessuno di questi ha aiutato con le prestazioni del gruppo di. Questo è un po 'quello che ha spinto la domanda in quanto sembra impossibile eliminare un gruppo sufficiente dalle prestazioni in questa situazione con SQLite. Immagino che questo sia solo uno dei limiti di avere un database incorporato. – gmn

1

Attenzione: non conosco nulla delle possibili complessità di SQLite e dei suoi piani di esecuzione.

Hai sicuramente bisogno di indici su a.id1, b.id1, b.id2 e c.id2. Penso che un indice composito (b.id1, b.id2) potrebbe produrre un piccolo aumento delle prestazioni. Lo stesso vale per (a.id1, a.Name, a.Description).

2

Dal SQLite query optimization overview:

Quando si effettua una ricerca indicizzata di una riga, la procedura usuale è quello di fare una ricerca binaria sull'indice di trovare la voce di indice, quindi estrarre l'identificativo dall'indice e l'uso che rowid per fare una ricerca binaria sulla tabella originale. Quindi una tipica ricerca indicizzata implica due ricerche binarie. Se, tuttavia, tutte le colonne che dovevano essere recuperate dalla tabella sono già disponibili nell'indice stesso, SQLite utilizzerà i valori contenuti nell'indice e non cercherà mai la riga della tabella originale. Ciò consente di salvare una ricerca binaria per ogni riga e può far sì che molte query vengano eseguite due volte più velocemente.

Per qualsiasi altro RDBMS, direi di inserire un indice cluster su b.id1 e c.id2. Per SQLite, potrebbe essere meglio includere qualsiasi colonna di be c che si desidera cercare anche in quegli indici.

+0

Gli indici di copertura esistono praticamente in tutti gli RDBMS e hanno lo stesso effetto sulle ricerche. Il problema è che gli indici di grandi dimensioni danneggiano le prestazioni di inserimento/aggiornamento e pertanto è necessario destreggiarsi tra le prestazioni di aggiornamento e selezionare le prestazioni. – Donnie

+0

Grazie per la risposta, per favore scusa la mia ignoranza qui, ma stai dicendo che è possibile in SQLite creare un indice che includa colonne da più tabelle, simili a una vista indicizzata in SQLServer? – gmn

+1

Beh no, stavo dicendo che quando si crea un indice su B, non basta creare l'indice su B.id ma includere anche tutte le colonne di dati necessarie da B nell'indice. Questo ti farà risparmiare una ricerca binaria per quelle colonne di dati. In un altro DBMS potresti probabilmente essere ancora più veloce includendo colonne da più tabelle in un indice, ma SQLite non è così avanzato. – thomaspaulb

0

Dal momento che non si sta utilizzando gli altri tavoli per le colonne di ritorno, forse questo sarà più veloce:

SELECT DISTINCT a.Name, a.Description 
FROM a, b, c 
WHERE a.id1 = b.id1 
AND b.id2 = c.id2 

Guardando le colonne restituite, poiché i criteri sembra essere solo che devono essere collegati da a a b a c, è possibile cercare tutte le coppie uniche a.Name e a.Description.

SELECT DISTINCT a.Name, a.Description 
FROM a 
WHERE a.id1 IN (
SELECT b.id1 
FROM b 
WHERE b.id2 IN (
    SELECT c.id2 
    FROM c 
) 
) 

Oppure, a seconda se ogni coppia di a.Name e a.Description è già unica, ci dovrebbe essere qualche guadagno a scoprire prima le uniche id poi vanno a prendere le altre colonne.

SELECT a.Name, a.Description 
FROM a 
WHERE a.id1 IN (
SELECT DISTINCT a.id1 
FROM a 
WHERE a.id1 IN (
    SELECT b.id1 
    FROM b 
    WHERE b.id2 IN (
    SELECT c.id2 
    FROM c 
    ) 
) 
) 
1

Penso agli indici su a.id1 e b.id2 darebbe circa tanto beneficio come si potrebbe ottenere in termini di join. Ma SQLite offre EXPLAIN e potrebbe aiutarti a determinare se c'è un evitabile in termini di efficienza nel piano di esecuzione corrente.