【问题标题】:Several layers of nested subqueries with Exists/In, best performance?Exists/In 的多层嵌套子查询,性能最佳?
【发布时间】:2013-03-13 13:50:03
【问题描述】:

我正在处理一些相当大的搜索功能查询。有许多不同的输入,因此查询非常大。它已经发展到有 2 层深的嵌套子查询的地方。性能已经成为那些将返回大型数据集并且可能必须筛选大量记录才能做到这一点的问题。比较少的那些表现很好,但其中一些变得非常糟糕。该数据库是 DB2 并且具有所有必要的索引,因此这应该不是问题。我想知道如何最好地编写/重写这些查询以执行,因为我不太确定优化器将如何处理它。我显然不能在这里倾倒整个东西,但这里有一个例子:

Select A, B 
from TableA
      --A series of joins--
WHERE TableA.A IN (
      Select C 
      from TableB
              --A few joins--
      WHERE TableB.C IN (
              Select D from TableC
              --More joins and conditionals--
              )
       )

还有很多条件句贯穿始终,其中绝大多数是简单的相等。你明白了。子查询不向初始查询提供任何数据。它们的存在只是为了过滤结果。我早期遇到的一个问题是后端被编写为包含许多部分查询字符串,这些字符串被组装到最终查询中(由于搜索选项有 100 多种可能的组合,编写查询根本不可行对于每个),这使整个方法有点复杂。我想知道 EXISTS 而不是 IN 是否可能在一个或两个级别上有所帮助,或者另一组连接而不是子查询,或者可能在 TableC 的初始查询之上使用 WITH 等。我肯定希望消除瓶颈并希望人们可能对如何处理这个问题有任何反馈。

我可能还应该补充一点,两个子查询中都有潜在的联合。

【问题讨论】:

    标签: sql db2 nested subquery


    【解决方案1】:

    改用内部连接可能会有所帮助。

    Select A, B
    from TableA
      inner join TableB on TableA.A = TableB.C
      inner join TableC on TableB.C = TableC.D
    

    数据库是为连接而设计的,但优化器可能无法确定它可以将索引用于子查询。相反,它可能会尝试运行子查询,将结果保存在内存中,然后进行线性搜索以评估每条记录的 IN 运算符。

    现在,您说您拥有所有必要的索引。考虑一下。

    如果一个可选条件是 TableC.E = 'E' 而另一个可选条件是 TableC.F = 'F', 那么两者的查询将需要字段 TableC.E AND TableC.F 的索引。现在许多年轻的程序员认为他们可以在 TableC.E 上拥有一个索引,在 TableC.F 上拥有一个索引,这就是他们所需要的。实际上,如果查询中有两个字段,则需要对这两个字段都建立索引。

    因此,对于 100 多个组合,“所有必要的索引”可能需要 100 多个索引。

    现在 TableC.E 上的索引,TableC.F 可以在有 TableC.E 条件但没有 TableC.F 条件的查询中使用,但不能在有 TableC.F 条件但没有 TableC 时使用。 E 条件。

    数百个索引?我该怎么办?

    实际上并没有那么糟糕。假设您有 N 个可选条件,它们要么在 where 子句中,要么不在。组合的数量是第 2 到第 n 个,或者对于数百个组合,N 是组合数量的 log2,介于 6 和 10 之间。此外,这些 log2 条件分布在三个表中。有些数据库支持多表索引,但我不确定 DB2 是否支持,所以我会坚持使用单表索引。

    所以,我要说的是,对于 TableC.E 和 TableC.F 示例,仅具有以下索引是不够的:

    TableB ON C
    TableC ON D
    TableC ON E
    TableC ON F
    

    一方面,优化器必须选择要使用的最后三个索引中的一个。最好在最后两个索引中包含 D 字段,这给了我们

    TableB ON C
    TableC ON D, E
    TableC ON D, F
    

    这里,如果字段 E 和 F 都不在查询中,它仍然可以在 D 上建立索引,但如果其中一个在查询中,它可以同时在 D 和另一个字段上建立索引。

    现在假设您有 10 个字段的索引,这些字段可能在查询中,也可能不在查询中。为什么索引中只有一个字段?为什么不按出现在查询中的可能性降序添加其他字段?

    在规划索引时考虑这一点。

    【讨论】:

    • 索引非常彻底,执行计划目前仅显示索引扫描。一直使用连接可能需要更多索引,但它们对于当前查询来说已经足够了。
    • DB2 可能正在将IN 重写为JOIN “在幕后”,所以结果可能是相同的,无论哪种方式。看看this Info Center entry。
    • @bhamby 是的,我知道数据库优化器会重写查询,并且通常可以找出一个查询等同于另一个可以索引的查询。我只是说内部连接对优化器来说更明显,并且不太可能错过即将使用索引。
    • @user1017413 是的,它总是使用 AN 索引,但它可以使用具有更多字段的更好索引吗?
    • @bhamby 我的意思是,如果您执行内部连接,那么 DB2 肯定会知道如何索引它。如果您使用子查询,DB2 优化器可能会意识到它等同于内部连接并以相同的方式对其进行索引,或者它可能会意识到查询不相关,沿着另一条逻辑路径走,首先执行静态内部查询,并对 IN 子句进行线性搜索。
    【解决方案2】:

    我发现“IN”谓词适用于小型子查询,而“EXISTS”适用于大型子查询。 尝试使用“EXISTS”谓词执行大型查询。

    SELECT A, B 
    FROM TableA
    WHERE EXISTS (
          Select C 
          FROM TableB
          WHERE TableB.C = TableA.A)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多