我有一个这样的数据库模式:
CREATE TABLE callchain(
seq_no INT,
entry_oid INT,
leave_oid,
tid INT,
pid INT,
depth
);
CREATE UNIQUE INDEX callchain_idx on callchain(seq_no);
对于这个表中的每一行,我想选择最近的对应的下一行,其中tid
,pid
是相同的,leave_oid
不是null,entry_oid
是null,seq_no
大于当前seq_no
(seq_no对于一个表是唯一的),并且其中深度比当前的深度小1。
我为此写了一个查询:
select *, (select min(seq_no) from callchain where seq_no > cc.seq_no and cc.pid = pid and cc.tid = tid and leave_oid not null and depth = cc.depth -1) from callchain as cc;
不幸的是,这个查询在1000000条记录上花费了太长的时间(几乎是无止境的)(我需要100000000条记录之类的东西……)
基本上,这是一个运行程序的跟踪记录。其中entry_oid
在函数入口时不为null,leave_oid
在函数出口时不为null。我想找到每个函数入口记录的函数出口记录。例如,有一张table:
seq_no entry_oid leave_oid tid pid depth
-------- --------- --------- --- --- -----
2 117544 24 21 1
3 117545 24 21 2
4 117556 24 21 1
5 117557 24 21 0
6 117558 24 21 -1
7 117546 24 21 0
8 117547 24 21 1
9 117559 24 21 0
10 117548 24 21 1
11 117549 24 21 2
12 117560 24 21 1
13 117561 24 21 0
14 117562 24 21 -1
15 117563 24 21 -2
对于行#7(入口点),对应的出口点将是行#14。
我试着写JOIN查询,如下所示:
select A.seq_no, min(B.seq_no), B.leave_oid from callchain as A inner join callchain as B on A.seq_no < B.seq_no AND A.tid=B.tid AND A.pid=B.pid AND B.leave_oid NOT NULL AND B.depth = A.depth - 1 GROUP BY A.seq_no ORDER BY A.seq_no;
但我没有大的成功与此查询。这也需要很长的时间。:-(
对于相关子查询,正如我所理解的,数据首先被seq_no
除以,然后被pid/tid/depth
除以(反之亦然)。并且单一索引不足以满足这两种情况(索引seq_no
或索引pid/tid/depth
)。在数据被划分之后,先前构建的索引变得无效,所以SQLite引擎构建临时B树,所有这些都变得太慢了。
为什么连接查询很慢我不明白,看起来没有任何临时索引的建立,只是算法复杂度太大。
我想问,我如何重写我的查询和/或重新设计一个数据库,以快速执行我想要的查询(在几秒钟内)?
我使用SQlite引擎作为C++程序的嵌入式数据库。我想避免切换到全功能的DBMS。
1条答案
按热度按时间qgzx9mmu1#
增加覆盖索引
由于您的查询过滤器和连接在
tid
,pid
,seq_no
,depth
和leave_oid
上,因此在这些列上添加覆盖索引将允许查询纯粹从索引中得到满足,而不会命中主表:首先使用CTE进行过滤
在CTE中首先应用leave_oid和depth的条件,以在连接之前减少数据集:
使用IN子查询而不是join
这可能通过直接索引查找执行得更好: