2011-03-18 6 views
3

J'ai un t1 table et deux index:Comment optimiser un index SQLite?

create index if not exists timeindex on t1(time, "Bytes Received") 
create index if not exists filenameindex on t1(filename) 

La requête suivante exécute assez vite:

select "Bytes Received" from t1 where time>="11:19:31.18" and time <= "11:19:36.18" 

Mais quand j'ajoute une condition supplémentaire à l'instruction WHERE la requête ralentit énormément

select "Bytes Received" 
    from t1 
    where time>="11:19:31.18" and time <= "11:19:36.18" 
    and filename = "SE12.log" 

J'ai essayé de créer un nouvel index t1(time, "Bytes Received", filename) mais la vitesse d'exécution n'a pas changé.

Comment dois-je modifier les index dans le tableau pour accélérer la requête?

Répondre

4

Utilisez BETWEEN et l'indice suivant:

CREATE INDEX IF NOT EXISTS fntimeindex ON t1(filename ASC, time ASC); 
SELECT "Bytes Received" 
    FROM t1 INDEXED BY fntimeindex 
    WHERE filename = 'SE12.log' 
    AND time BETWEEN '11:19:31.18' AND '11:19:36.18'; 

Notez également que dans les chaînes SQL sont placées entre guillemets simples (guillemets doubles sont pour la table, les schémas et les noms de colonnes).

+0

Merci, Benoit! Que se passerait-il si j'incluais une autre condition, par ex. "et ms = 'ms1'"? Dois-je ajouter "ms" à l'index t1 (nom de fichier ASC, heure ASC, ms ASC)? – smirnoffs

+0

Peut-être que vous devriez lire l'ensemble [chose] (http://use-the-index-luke.com/sql/preface) ici et aussi la section ["ordre des colonnes compte"] (http: //www.itbully. com/articles/sql-indexing-et-performance-part-4-design-considerations) là .. – Benoit

1

La réponse de Benoit est correcte dans la mesure où BETWEEN dit à Sqlite qu'une plage arrive, donc il n'a qu'à rechercher l'index une fois pour les deux termes dans l'expression AND (sinon, il chercherait deux fois l'index, côté main, et une fois pour la droite). Cela réduit de moitié le nombre de documents consultés. (Si vous exécutez EXPLAIN QUERY PLAN dans l'outil de ligne de commande sqlite, cela s'affichera clairement.)

Cependant, le planificateur de requêtes de Sqlite aime utiliser 1 index par table. Pour contourner ce problème, la solution canonique consiste à réécrire explicitement la requête comme une série de sous-SÉCANTES Selects:

SELECT "Bytes Received" FROM t1 WHERE ROWID IN 
(SELECT ROWID FROM t1 WHERE filename = 'SE12.log' 
INTERSECT 
SELECT ROWID FROM t1 WHERE time BETWEEN '11:19:31.18' AND '11:19:36.18' 
) 

Vous pouvez évidemment ajouter plus de sous-traiter à des termes choisit supplémentaires. L'utilisation de INDEXED BY ne devrait pas être nécessaire, puisqu'il ne s'agit pas d'un "mécanisme d'indication", mais plutôt d'une exigence (qui provoquera une erreur si un changement de schéma fait disparaître l'index - mais c'est peut-être ce que vous voulez.)