Oracle 1:n高效查询

时间:2012-06-06 09:56:30

标签: sql database oracle

我有两个表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上的触发器来更新新列。但这也不可行,因为您无法查询触发器所在的同一个表。

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

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

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

您可以创建一个视图,其中包含自拍摄快照以来更新的物化视图和原始数据(并且可能删除不再有效的更新条目)但不知道如何使用数据/是否是永远不会更新,而不仅仅是添加到它不是真的可以建议具体细节。

答案 1 :(得分:0)

<强> 1。将WM_CONCAT替换为LISTAGGCOLLECT

由于SQL和PL / SQL之间频繁的上下文切换,大字符串聚合可能非常昂贵。 WM_CONCATSTRAGG非常受欢迎,但效率非常低。如果您使用的是11gR2,请始终使用LISTAGG。如果您尚未使用11gR2,请使用COLLECT方法。 This page解释了不同的方法,并进行了一些性能比较。

<强> 2。物化视图。

我知道你说你已经尝试过了,而且我对物化观点没有很多经验,但我认为他们应该在这种情况下工作。 rowid物化视图无法正常工作,但primary key materialized view应该有效。

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

第3。解释计划。

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


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