【发布时间】:2014-10-20 00:10:52
【问题描述】:
我有一张有几十万行的表格。 (这是一个预先计算好的表,表示词的词元与其他大表之间的关系。) 我需要进行多项选择以找到不同条目的组合,即我必须使用“AS”来进行选择……从 ltc 作为 l0,ltc 作为 l1,ltc 作为 l2……排序…… 查询的速度取决于排序:不排序是几毫秒,排序是几分钟。据我所知,这是由于 Sqlite 为排序而构建的临时 B-Tree,即使我在排序列“nr”上有一个索引。我不明白为什么 Sqlite 不使用这个索引。
CREATE TABLE ltc
(nr INTEGER, lemId INTEGER, cId INTEGER, bId INTEGER,
-- UNIQUE (lemId, cId, bId),
-- if I add this uniqueness constraint, strangely enough it doesn’t use my index at all, even at a simple ORDER BY.
PRIMARY KEY(nr,lemId,cId),
FOREIGN KEY(lemId) REFERENCES lems(rowid),
FOREIGN KEY(cId) REFERENCES cs(rowid),
FOREIGN KEY(bId) REFERENCES bs(rowid) )
CREATE INDEX nri ON ltc(nr)
这是我的选择命令的精简版:
SELECT l0.nr,l1.nr,l2.nr
FROM ltc as l0, ltc as l1, ltc as l2
WHERE
l0.lemId IN (1001) -- in reality 1001 is some simple sub select.
AND l1.lemId IN (1002,1003)
AND l2.lemId IN (1004 )
ORDER BY
l0.nr,
l1.nr,
l2.nr
LIMIT 10;
EXPLAIN QUERY PLAN 给出:
(0, 0, 0, u'SCAN TABLE ltc AS l0')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 1')
(1, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 1, 1, u'SCAN TABLE ltc AS l1')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 2')
(2, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 2, 2, u'SCAN TABLE ltc AS l2')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 3')
(3, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 0, 0, u'USE TEMP B-TREE FOR ORDER BY')
删除了 ORDER BY(或减少到只有一列 order by
l0.nr):
(0, 0, 0, u'SCAN TABLE ltc AS l0 USING COVERING INDEX sqlite_autoindex_ltc_1')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 1')
(1, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 1, 1, u'SCAN TABLE ltc AS l1 USING COVERING INDEX sqlite_autoindex_ltc_1')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 2')
(2, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 2, 2, u'SCAN TABLE ltc AS l2 USING COVERING INDEX sqlite_autoindex_ltc_1')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 3')
(3, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
我尝试了各种单一和组合的 indeces,但似乎没有任何区别。
问题似乎是双重排序本身而不是双重选择:即使是无用的双重 ORDER BY 也会创建一个临时 b 树(即使在这种情况下结果是立即的):
EXPLAIN QUERY PLAN SELECT ltc.nr
FROM ltc
WHERE
ltc.lemId = 716
ORDER BY
ltc.nr,
ltc.nr
LIMIT 10;
(0, 0, 0, u'SCAN TABLE ltc')
(0, 0, 0, u'USE TEMP B-TREE FOR ORDER BY')
SQLite ORDER BY performance issue 据说查询不能按来自不同表的索引排序。这是这里的问题吗?有办法吗?这是 Sqlite 特定的限制还是所有 SQL 系统都这样做?
编辑:
添加索引后,按照 CL 的建议,性能问题依然存在。 以一个包含四个搜索词的更完整的查询为例:
select l0.nr,l1.nr,l2.nr,l3.nr
from ltc as l0, ltc as l1, ltc as l2, ltc as l3
where
l0.lemId in (select rowid from lems where lems.lem = "catch" )
and l1.lemId in (select rowid from lems where lems.lem = "cause" )
and l2.lemId in (select rowid from lems where lems.lem = "score" )
and l3.lemId in (select rowid from lems where lems.lem = "guest" )
order by
l0.nr asc
LIMIT 10;
给出了这样的解释:
(0, 0, 0, u'SEARCH TABLE ltc AS l0 USING INDEX lid (lemId=?)')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 1')
(1, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 1, 1, u'SEARCH TABLE ltc AS l1 USING INDEX lid (lemId=?)')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 2')
(2, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 2, 2, u'SEARCH TABLE ltc AS l2 USING INDEX lid (lemId=?)')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 3')
(3, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 3, 3, u'SEARCH TABLE ltc AS l3 USING INDEX lid (lemId=?)')
(0, 0, 0, u'EXECUTE LIST SUBQUERY 4')
(4, 0, 0, u'SEARCH TABLE lems USING COVERING INDEX lem (lem=?)')
(0, 0, 0, u'USE TEMP B-TREE FOR ORDER BY')
(不再进行完整扫描。)
但是:时间:388 秒!!!
当删除 order by 时,我得到完全相同的解释减去最后一个临时 B 树!
时间:0.00025 秒!!!
这个查询对应于某种连接。我还可以将查询表示为(内部)连接(带条件)。这可能是时间似乎随着搜索词数量呈指数增长的原因:{1 个搜索词:0.08 秒,2:0.5,3:3,4:9,5:116,...} 但不知何故,我不太明白为什么数据库不能简单地使用 nr 列上的索引进行排序。毕竟,只是需要排序的结果很多,每个结果都包含 nr。
按照 CL 的建议,我将根本问题放在一个新问题中:Selecting tuples of lines from an Sqlite table and sorting the tuples efficiently
【问题讨论】:
-
不要改问题! (这个问题是是否可以使用索引进行排序,答案是“否”。)针对实际问题提出一个新问题(并澄清
cId的值应该相同还是不同;当前描述自相矛盾)。还包括示例输入/输出数据。 -
好吧,你是对的。这是新问题:[stackoverflow.com/questions/25526087/…
标签: sqlite indexing sql-order-by explain