0

我有两个表 A 和 B,其中 A 中的一条记录映射到 B 中的几条记录。有一个查询显示表 A 的记录,以及表 B 中的所有映射记录在一行中,例如:

TABLE A
--------
ID  Name  Tag ......
1    X    213
2    Y    222

TABLE B
--------
ID    ACCESS_AREA
1     101
1     104
1     105
2     101
2     103

查询类似于:

SELECT ID,
       Name,
       Tag ,.....,
       (SELECT WM_CONCAT(ACCESS_AREA)
          FROM B
          WHERE ID = A.ID ) Access_areas
  FROM A

虽然上述方法有效,但查询的性能非常低,因为两个表中的记录数都非常大。对结果进行任何过滤或排序都会access_areas导致性能进一步下降。

我们考虑过使用物化视图预先计算值,以便它成为简单的连接,但 mv 不允许使用聚合函数在提交时快速刷新此类查询。

另一种选择是向表 A 添加一列,其中包含来自 B 的计算值,并在表 B 上使用触发器来更新新列(如果进行了任何更改)。但这也不可行,因为您无法查询触发器所在的同一个表。

作为最后的手段,我们决定实现第二个选项并通过应用程序代码更新列,这非常繁琐。

有任何想法吗?

4

2 回答 2

1

您没有显示查询的 EXPLAIN 计划,也没有显示表的索引。但更重要的是,您还没有告诉我们您正在使用这些数据做什么——为什么您需要一次访问大量数据?为什么你需要对结果进行去污?

您可以创建一个包含物化视图和自拍摄快照以来更新的原始数据的视图(并可能删除不再有效的更新条目),但不了解数据的使用方式/是否更新过而不仅仅是添加到它实际上不可能就具体细节提供建议。

于 2012-06-06T10:14:19.140 回答
0

1. 替换WM_CONCATLISTAGGCOLLECT

由于 SQL 和 PL/SQL 之间频繁的上下文切换,大型字符串聚合可能非常昂贵。 WM_CONCAT, 和STRAGG, 非常流行,但它们都非常低效。如果您使用的是 11gR2,请始终使用LISTAGG. 如果您还没有使用 11gR2,请使用该COLLECT方法。 此页面解释了不同的方法并进行了一些性能比较。

2.物化视图。

我知道你说你已经尝试过了,而且我对物化视图没有太多经验,但我认为它们应该在这种情况下工作。rowid 物化视图不起作用,但主键物化视图应该。

(除非有其他特定原因阻止它,在这种情况下,我们可能需要所有细节来解决问题:表的完整查询和 DDL、物化视图和物化视图日志。)

3. 解释计划。

正如 symcbean 所提到的,这可能是一个计划问题。如果您只使用少量行,是否正在使用索引?但除了解释计划之外,我们还需要了解您对此查询的期望。如果查询需要一秒钟,但返回 200KB 的数据,那么您的网络或浏览器可能是真正的瓶颈。


我不确定#2 或#3 是否会有所帮助,但您应该始终实施#1。我认为WM_CONCATSTRAGG成为错误 - 当有更好的选择时,没有充分的理由使用它们。

于 2012-06-07T09:57:50.487 回答