我有两个表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上的触发器来更新新列。但这也不可行,因为您无法查询触发器所在的同一个表。
作为最后的手段,我们决定实施第二个选项并通过应用程序代码更新列,这非常繁琐。
有什么想法吗?
答案 0 :(得分:1)
您没有显示查询的EXPLAIN计划,也没有显示表的索引。但更重要的是,您没有告诉我们您使用这些数据做了什么 - 为什么您需要一次访问大量数据?为什么需要对结果进行去噪?
您可以创建一个视图,其中包含自拍摄快照以来更新的物化视图和原始数据(并且可能删除不再有效的更新条目)但不知道如何使用数据/是否是永远不会更新,而不仅仅是添加到它不是真的可以建议具体细节。
答案 1 :(得分:0)
<强> 1。将WM_CONCAT
替换为LISTAGG
或COLLECT
。
由于SQL和PL / SQL之间频繁的上下文切换,大字符串聚合可能非常昂贵。 WM_CONCAT
和STRAGG
非常受欢迎,但效率非常低。如果您使用的是11gR2,请始终使用LISTAGG
。如果您尚未使用11gR2,请使用COLLECT
方法。 This page解释了不同的方法,并进行了一些性能比较。
<强> 2。物化视图。
我知道你说你已经尝试过了,而且我对物化观点没有很多经验,但我认为他们应该在这种情况下工作。 rowid物化视图无法正常工作,但primary key materialized view应该有效。
(除非有其他一些具体原因阻止它,在这种情况下,我们可能需要所有细节来解决问题:表格,物化视图和物化视图日志的完整查询和DDL。)
第3。解释计划。
正如symcbean所提到的,这可能是一个计划问题。如果您只使用少量行,是否使用了索引?但除了解释计划,我们还需要了解您对此查询的期望。如果查询需要一秒钟,但返回200KB的数据,那么您的网络或浏览器可能是真正的瓶颈。
我不确定#2或#3是否会有所帮助,但您应该始终实施#1。我认为WM_CONCAT
和STRAGG
是错误的 - 当有更好的选择时,没有充分的理由使用它们。