J'ai une base de données sqlite avec deux tables, chacune avec 50 000 lignes, contenant les noms de (fausses) personnes. J'ai construit une requête simple pour savoir combien de noms (prénom, initiale, prénom) sont communs aux deux tables:
select count(*) from fakenames_uk inner join fakenames_usa on fakenames_uk.givenname=fakenames_usa.givenname and fakenames_uk.surname=fakenames_usa.surname and fakenames_uk.middleinitial=fakenames_usa.middleinitial;
Lorsqu'il n'y a pas d'index sauf sur les clés primaires (sans rapport avec cette requête), il s'exécute rapidement:
[james@marlon Downloads] $ time sqlite3 generic_data_no_indexes.sqlite "select count(*) from fakenames_uk inner join fakenames_usa on fakenames_uk.givenname=fakenames_usa.givenname and fakenames_uk.surname=fakenames_usa.surname and fakenames_uk.middleinitial=fakenames_usa.middleinitial;"
131
real 0m0.115s
user 0m0.111s
sys 0m0.004s
Mais si j'ajoute des index aux trois colonnes de chaque table (six index en tout):
CREATE INDEX `idx_uk_givenname` ON `fakenames_uk` (`givenname` )
//etc.
puis il s'exécute douloureusement lentement:
[james@marlon Downloads] $ time sqlite3 generic_data.sqlite "select count(*) from fakenames_uk inner join fakenames_usa on fakenames_uk.givenname=fakenames_usa.givenname and fakenames_uk.surname=fakenames_usa.surname and fakenames_uk.middleinitial=fakenames_usa.middleinitial;"
131
real 1m43.102s
user 0m52.397s
sys 0m50.696s
Y a-t-il une rime ou une raison à cela?
Voici le résultat de EXPLAIN QUERY PLAN
la version sans index:
0|0|0|SCAN TABLE fakenames_uk
0|1|1|SEARCH TABLE fakenames_usa USING AUTOMATIC COVERING INDEX (middleinitial=? AND surname=? AND givenname=?)
C'est avec des index:
0|0|0|SCAN TABLE fakenames_uk
0|1|1|SEARCH TABLE fakenames_usa USING INDEX idx_us_middleinitial (middleinitial=?)
SELECT c FROM t WHERE a=1 AND b=2
, l'index t(a,b,c)
couvre mais t(a,b)
ne l'est pas. L'avantage de couvrir les indices est que le résultat de la requête entière peut être extrait directement de l'index, tandis que les indices non couvrant trouvent rapidement les lignes pertinentes, mais il doit toujours se référer aux données du tableau principal pour sélectionner les valeurs.
middleinitial
,surname
etgivenname
)?