我有一个带两个表的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
)?