Mam bazę danych sqlite z dwiema tabelami, każda zawierająca 50 000 wierszy, zawierającymi nazwiska (fałszywych) osób. Zbudowałem proste zapytanie, aby dowiedzieć się, ile jest imion (imię, inicjał środkowy, nazwisko) wspólnych dla obu tabel:
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;
Gdy nie ma żadnych indeksów poza kluczami głównymi (nieistotnymi dla tego zapytania), uruchamia się szybko:
[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
Ale jeśli dodam indeksy do trzech kolumn w każdej tabeli (łącznie sześć indeksów):
CREATE INDEX `idx_uk_givenname` ON `fakenames_uk` (`givenname` )
//etc.
potem działa boleśnie powoli:
[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
Czy jest w tym jakikolwiek rym lub powód?
Oto wynik EXPLAIN QUERY PLAN
dla wersji bez indeksów:
0|0|0|SCAN TABLE fakenames_uk
0|1|1|SEARCH TABLE fakenames_usa USING AUTOMATIC COVERING INDEX (middleinitial=? AND surname=? AND givenname=?)
Jest to z indeksami:
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
indeks t(a,b,c)
obejmuje, ale t(a,b)
nie jest. Zaletą pokrycia indeksów jest to, że cały wynik zapytania można wyciągnąć bezpośrednio z indeksu, podczas gdy niekryjące indeksy szybko znajdują odpowiednie wiersze, ale nadal muszą odwoływać się do danych z głównej tabeli, aby wybrać wartości.
middleinitial
,surname
igivenname
)?