我想创建一个图表,其节点是使用递归查询从数据集(bidirectional_edges)中选择的。基本上,结果表以源节点(由用户选择)开始,并加入与第一个节点相关的目标节点。接下来,递归查询选择已经选择的最后一个的目标。当一个节点有超过20个关系时,我不想显示与之相关的下一个节点,因此我通过“删失”调用了超过20个关系的节点。有两种类型的关系:一种和两种,因此,两种方式可以审查节点。
问题是我构建代码的方式在节点数和节点数很大时需要花费很多时间才能加载。我已经尝试通过标志在bidirectional_edges表中插入删失节点的信息,以消除与删失表的左连接,但运行时间并没有大大减少。 bidirectional_edges由SOURCE_ID和TARGET_ID索引。
有没有办法优化查询?我认为问题出现在带有多个AND和OR的where子句中。
以下是数据集bidirectional_edges,censored_nodes_one和censored_nodes_two的示例:
CREATE TABLE WORK.OUTPUT AS
SELECT
"CLAIM" AS SOURCE,
a.CLAIMID,
a.DXCODE
FROM
DW.CLAIMS_BAV (dbmaster=yes) AS a
inner join WORK.INPUT AS b
on a.CLAIMID = b.CLAIMID
WHERE
a.SITEID = '0001'
在下面的代码中,我将节点1作为第一个,并且只想带节点1,2,3,4,5和6.
CREATE TABLE bidirectional_edges (
SOURCE_ID integer NOT NULL,
TARGET_ID integer NOT NULL,
FLAG_ONE integer NOT NULL,
FLAG_TWO integer NOT NULL
);
INSERT INTO bidirectional_edges(SOURCE_ID, TARGET_ID, FLAG_ONE, FLAG_TWO)
VALUES
(1,2,1,0),
(1,3,0,1),
(2,5,1,1),
(2,6,0,1),
(2,7,1,0),
(2,8,1,0),
(2,9,1,0),
(2,10,1,0),
(2,11,1,0),
(2,12,1,0),
(2,13,1,0),
(2,14,1,0),
(2,15,1,0),
(2,16,1,0),
(2,17,1,0),
(2,18,1,0),
(2,19,1,0),
(2,20,1,0),
(2,21,1,0),
(2,22,1,0),
(2,23,1,0),
(2,24,1,0),
(2,25,1,0),
(2,26,1,0),
(2,27,1,0),
(2,28,1,0),
(2,29,1,0),
(2,30,1,0),
(3,4,1,1),
(3,31,0,1),
(3,32,0,1),
(3,33,0,1),
(3,34,0,1),
(3,35,0,1),
(3,36,0,1),
(3,37,0,1),
(3,38,0,1),
(3,39,0,1),
(3,40,0,1),
(3,41,0,1),
(3,42,0,1),
(3,43,0,1),
(3,44,0,1),
(3,45,0,1),
(3,46,0,1),
(3,47,0,1),
(3,48,0,1),
(3,49,0,1),
(3,50,0,1),
(3,51,0,1),
(3,52,0,1),
(3,53,0,1),
(3,54,0,1),
(3,55,0,1)
;
CREATE TABLE censored_nodes_one (
node integer NOT NULL,
relations integer NOT NULL
);
INSERT INTO censored_nodes_one(node, relations)
VALUES
(2,25)
;
CREATE TABLE censored_nodes_two (
node integer NOT NULL,
relations integer NOT NULL
);
INSERT INTO censored_nodes_two(node, relations)
VALUES
(3,26)
;
下面是此查询的查询计划:
with recursive search_graph("NODE", "DEPTH", "PATH") as (
select
1 AS NODE,
0 AS DEPTH,
ARRAY[1] as PATH
union
select
be.TARGET_ID as NODE,
sg."DEPTH" + 1 as DEPTH,
sg."PATH" || be.TARGET_ID as PATH
from
bidirectional_edges as be
inner join
search_graph as sg on
sg."NODE" = be.SOURCE_ID
left join
censored_nodes_one as cno on
sg."NODE" = cno.node
left join
censored_nodes_two as cnt on
sg."NODE" = cnt.node
where
sg."DEPTH" < 2 and
not (be.TARGET_ID) = any(sg."PATH") and
(
(be.FLAG_ONE = 1 and cno.node is null) OR
(be.FLAG_TWO = 1 and cnt.node is null)
)
)
select *
from
search_graph
我需要使用的表有大约740.000.000行,所以当我尝试运行这个递归查询时,需要很长时间。
答案 0 :(得分:0)
我无法真正提供解决方案 - 我也尝试过与@wildplasser建议类似的东西,但无法让它运行。
但是,我有一些想要分享的想法;也许他们可以帮助你解决这个问题:
在每次迭代中必须加入(或在NOT EXISTS
子句中引用)两个其他表似乎很麻烦。如果你可以摆脱它,你的查询会快得多。
由于所有内容都在sg."NODE"
上加入(自己帮忙并使用小写标识符),您只需将另一个布尔字段添加到bidirectional_edges
并将其设置为{{1}的结果提前条件。
首先,您运行一个与OR
和censored_nodes_one
连接的查询并相应地设置布尔字段,然后仅使用censored_nodes_two
运行递归查询。
如果因某种原因无效,您可以使用CTE执行类似操作:
bidirectional_edges
CTE结果的大尺寸可能是个问题。
不要忘记使用索引 - 例如,您的查询看起来可能会从WITH dbe_flagged AS (
perform the join and provide an "artificial" boolean flag
),
RECURSIVE search_graph AS (
now run your recursive query on "dbe_flagged"
)
SELECT * FROM search_graph;
上的索引中获利。