非常快速地从NOT IN查询返回结果

时间:2016-09-28 11:16:27

标签: oracle query-performance notin anti-join

我们已经建立了一个系统,我们收集了一些项目(> 100万),以及处理它的一些事情。每个处理器应该只处理每个项目一次,并且处理器具有层次结构。

我们目前的实施是进行“处理”。表跟踪每个处理器已经完成的工作:

CREATE TABLE items (id NUMBER PRIMARY KEY, ...)
CREATE TABLE itemsProcessed(
    item NUMBER REFERENCES items(id),
    processor NUMBER)

我们的查询是这样的(itemsProcessed上有相关索引) - 我们使用NOT IN过滤掉当前处理器或其祖先已经处理过的项目:

SELECT ... FROM items i WHERE <additional queries on items>
    AND id NOT IN (SELECT item FROM itemsProcessed WHERE processor IN (1, 2))

当处理后的表变得非常大时,此查询开始花费很长时间(几秒钟),因为它必须在开始返回第一个项目之前进行大量过滤(查询计划使用散列反连接)< / p>

我们需要此查询以非常快速地返回前几个项目 - 理想情况下返回<500> 500ms以下的第一项。这意味着它无法迭代items并过滤掉itemsProcessed中的内容。所以我们需要一些方法来对itemsitemsProcessed的联接做一个否定索引(我们已经在mongo上完成了这个,但是oracle doens似乎能够做到类似的事情)

这可能与Oracle有关吗?

3 个答案:

答案 0 :(得分:1)

您可以尝试在查询中添加/*+ first_rows */提示

SELECT /*+ first_rows (10) */... FROM items i ...

或尝试先选择未处理的项目而不是<additional queries on items>

with i_to_process AS
(
  SELECT item  FROM items
  minus 
  SELECT item FROM itemsProcessed WHERE processor IN (1, 2)
)
select * from i_to_process
where 
<additional queries on items>

答案 1 :(得分:0)

IMO这是一个设计问题。当您尝试包含尚未处理的项目时,您尝试排除已处理的项目。已处理的项目清单将继续增长;要处理的项目列表将保持较小。我建议您创建一个要处理的项目表,然后将其内部连接到查询中,而不是拥有已处理的项目表(itemProcessed),并在处理它们时从ITEMS_TO_BE_PROCESSED表中删除项目。 / p>

祝你好运。

答案 2 :(得分:0)

根据表的更新频率,您可以创建itemsNotProcessed的物化视图。处理将事先完成。您还可以对一个位进行非规范化处理,并将一个已处理的标志添加到items表中,并在该标志上添加一个位图索引。