У мене база даних sqlite з двома таблицями, кожна з яких містить 50 000 рядків, що містять імена (підроблених) людей. Я сконструював простий запит, щоб дізнатися, скільки імен (ім'я, середня ініціатива, прізвище) є спільними для обох таблиць:
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;
Якщо немає індексів, крім первинних ключів (що не стосується цього запиту), він запускається швидко:
[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
Але якщо додати індекси до трьох стовпців кожної таблиці (шість індексів у всіх):
CREATE INDEX `idx_uk_givenname` ON `fakenames_uk` (`givenname` )
//etc.
тоді вона болісно біжить повільно:
[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
Чи є якась рима або причина цього?
Ось результат EXPLAIN QUERY PLAN
для версії без індексів:
0|0|0|SCAN TABLE fakenames_uk
0|1|1|SEARCH TABLE fakenames_usa USING AUTOMATIC COVERING INDEX (middleinitial=? AND surname=? AND givenname=?)
Це з індексами:
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
індекс t(a,b,c)
охоплює, але t(a,b)
це не так. Перевага покриття індексів полягає в тому, що весь результат запиту можна витягнути безпосередньо з індексу, тоді як індекси, що не охоплюють, швидко знаходять відповідні рядки, але для вибору значень все-таки потрібно звернутися до даних основної таблиці.
middleinitial
,surname
іgivenname
)?