【问题标题】:Returning results from a NOT IN query very quickly从 NOT IN 查询中快速返回结果
【发布时间】:2017-02-06 08:08:54
【问题描述】:

我们有一个系统,我们有一个项目集合(> 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))

当处理的表变得非常大时,这个查询开始需要很长时间(几秒钟),因为它必须在开始返回第一项之前进行大量过滤(查询计划使用哈希反连接)

我们需要此查询以非常快速地返回前几项 - 理想情况下返回 500 毫秒以下的前几项。这意味着它不能遍历items 并过滤掉itemsProcessed 中的那些。所以我们需要在itemsitemsProcessed 的连接上做一个否定索引(我们已经在mongo上完成了这个,但是oracle似乎不能做类似的事情)

Oracle 可以做到这一点吗?

【问题讨论】:

  • 如果这样能得到更好的结果,你能试试吗? AND id IN (SELECT item FROM itemsProcessed WHERE processor &gt; 2)。如果您的processor 永远不是NULL,它应该返回相同的结果,但没有NOT 表达,这在某些情况下可能会更好地使用索引
  • 你的外键是否被索引 - 你说你有一个“相关”索引,还是你只索引processor?它们是什么类型的索引?执行计划显示什么?您是否尝试过使用 not exists 代替?如果您只想要前几行未处理的行,则使用 rownum 停止键?
  • 查询所用的时间,还取决于您在 中所做的事情。你在表上使用索引吗?
  • 所有其他 WHERE 子句都被索引,oracle 正在使用索引进行过滤。需要时间的是通过大量已处理项目的反连接搅动
  • @AlexPoole rownum 过滤器没有帮助 - 它必须在返回任何东西之前检查许多已经处理的项目,这就是需要时间的原因

标签: oracle query-performance notin anti-join


【解决方案1】:

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

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

或尝试先选择未处理的项目,然后再选择&lt;additional queries on items&gt;

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>

【讨论】:

    【解决方案2】:

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

    祝你好运。

    【讨论】:

    • 这也是我的首选解决方案,但不幸的是,每个项目创建时处理器列表都不知道。
    【解决方案3】:

    根据表的更新频率,您可以创建 itemsNotProcessed 的物化视图。处理将提前完成。你也可以去规范化一点,在 items 表中添加一个已处理的标志,并在该标志上添加一个位图索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-15
      • 2019-05-12
      • 1970-01-01
      • 2012-08-18
      • 2017-09-06
      • 2021-08-22
      相关资源
      最近更新 更多