Oracle - 快速刷新具有 LEFT JOINS 的物化视图更新非常慢
我在 Oracle 中有一个物化视图,其中包含需要很长时间才能更新的 LEFT JOIN。当我更新基础表时,运行需要 63914.765 秒(是的,几乎是 17 小时)。
我在同一个表上使用 LEFT JOIN,因为我想将数据从行转换为列。在此 Oracle 版本中,pivot 命令不可用,并且在 FAST REFRESH 物化视图上不允许使用 GROUP BY + CASE。
物化视图日志看起来像这样:
CREATE MATERIALIZED VIEW LOG ON Programmes_Titles
WITH PRIMARY KEY, rowid
INCLUDING NEW Values;
物化视图本身看起来像这样(它包含 700000 行,Programmes_Titles 表包含 900000 行):
CREATE MATERIALIZED VIEW Mv_Web_Programmes
REFRESH FAST ON COMMIT
AS
SELECT
t1.ProgrammeId,
t1.Title as MainTitle,
t2.Title as SecondaryTitle,
--Primary key
t1.Title_Id as t1_titleId,
t2.Title_Id as t2_titleId,
t1.rowid as t1_rowid,
t2.rowid as t2_rowid
FROM
Programmes_Titles t1,
Programmes_Titles t2
WHERE
t1.Titles_Group_Type = 'mainTitle'
AND t1.Programme_Id = t2.Programme_Id(+) AND t2.Titles_Group_Type(+) = 'secondaryTitle'
我使用的 UPDATE 语句是这样的:
UPDATE Programmes_Titles
SET Title = 'New title'
WHERE rowid = 'AAAL4cAAEAAAftTABB'
这个 UPDATE 语句需要 17 个小时。 当使用 INNER JOIN(删除 (+))时,需要几毫秒的时间。
我还尝试在 Mv_Web_Programmes 物化视图上添加索引,但这似乎也没有帮助。 (它仍然运行超过一分钟,这太慢了,我不会在每次更改后等待 17 个小时,所以它可能会改进更新)
所以我的问题是:为什么需要这么长时间来更新底层桌子?我该如何改进这个?
I have a Materialized view in Oracle that contains a LEFT JOIN which takes a very long time to update. When I update the underlying table it takes 63914.765 s to run (yes that is almost 17 hours).
I am using a LEFT JOIN on the same table, because I want to pivot the data from rows to columns. The pivot command is not available in this Oracle version, and using a GROUP BY + CASE is not allowed on a FAST REFRESH Materialized View.
The Materialized View Log looks like this:
CREATE MATERIALIZED VIEW LOG ON Programmes_Titles
WITH PRIMARY KEY, rowid
INCLUDING NEW Values;
The Materialized View itself looks like this (it contains 700000 rows, the Programmes_Titles table contains 900000 rows):
CREATE MATERIALIZED VIEW Mv_Web_Programmes
REFRESH FAST ON COMMIT
AS
SELECT
t1.ProgrammeId,
t1.Title as MainTitle,
t2.Title as SecondaryTitle,
--Primary key
t1.Title_Id as t1_titleId,
t2.Title_Id as t2_titleId,
t1.rowid as t1_rowid,
t2.rowid as t2_rowid
FROM
Programmes_Titles t1,
Programmes_Titles t2
WHERE
t1.Titles_Group_Type = 'mainTitle'
AND t1.Programme_Id = t2.Programme_Id(+) AND t2.Titles_Group_Type(+) = 'secondaryTitle'
The UPDATE statement I use is this:
UPDATE Programmes_Titles
SET Title = 'New title'
WHERE rowid = 'AAAL4cAAEAAAftTABB'
This UPDATE statement takes 17 hours.
When using an INNER JOIN (remove the (+)'s) it takes milliseconds.
I also tried adding INDEXES on the Mv_Web_Programmes Materialized View, but that did not seem to help either. (It still runs for more than a minute, which is way to slow, I am not waiting 17 hours after every change, so it might improved the UPDATE)
So my question is: Why does is take such a long time to UPDATE the underlying table? How can I improve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我已成功在 10.2.0.3 实例上重现您的问题。自连接和外连接似乎是主要问题(尽管 MV 的每一列都有索引,它最终在一分钟内完成了更新)。
起初我以为你可以使用聚合 MV:
不幸的是,正如你所注意到的,从 10g 包含 MIN 或 MAX 的 MV 只能在插入后提交时快速刷新(所谓仅插入 MV)。上述解决方案不适用于更新/删除(必须手动刷新 MV)。
您可以跟踪您的会话并打开跟踪文件以查看执行了哪些 SQL 查询,以便您可以发现是否可以通过索引对其进行优化。
I've managed to reproduce your problem on a 10.2.0.3 instance. The self- and outer-join seems to be the major problem (although with indexes on every column of the MV it finally did update in under a minute).
At first I thought you could use an aggregate MV:
Unfortunately, as you have noticed, as of 10g a MV that contains MIN or MAX can only be fast-refreshed on commit after insert (so called insert-only MV). The above solution would not work for update/delete (the MV would have to be refreshed manually).
You could trace your session and open the trace file to see what SQL query gets executed so that you can find if you can optimize it via indexes.
我们最近在 Oracle 11.2.0.3 上也遇到了这个问题
。在我们的例子中,由于功能影响,不可避免地要删除“OUTER JOIN”。
经过调查,发现 Oracle 在 MV 刷新 DML 中添加了令人讨厌的 HASH_SH(哈希半连接)提示。
没有任何效果,包括以下博客中提到的事情 -
http://www.adellera.it/blog/2010/03/11/fast-refresh-of-join-only-mvs-_mv_refresh_use_stats-and-locking-log-stats/#comment-2975
最后,一个隐藏的提示起作用了......(尽管一般来说,如果可能的话,应该通过在应用程序中进行更改来避免它)
Oracle Doc ID 1949537.1 建议将隐藏的 _mv_refresh_use_hash_sj 参数设置为 FALSE 应该可以防止它使用该提示。
这阻止了 CBO 使用 HASH_SJ 提示。
为了其他人的利益而将其发布在这里。
We too faced this issue recently on Oracle 11.2.0.3
In our case, it was unavoidable to to remove an 'OUTER JOIN' due to functional impact.
On investigation, it was found that Oracle was adding a nasty HASH_SH (Hash Semi Join) hint with MV refresh DML.
Nothing worked including things mentioned in following blog-
http://www.adellera.it/blog/2010/03/11/fast-refresh-of-join-only-mvs-_mv_refresh_use_stats-and-locking-log-stats/#comment-2975
In the end, a hidden hint worked...(though in general, it should be avoided by making change in application if possible)
Oracle Doc ID 1949537.1 suggests that setting the hidden _mv_refresh_use_hash_sj parameter to FALSE should prevent it using that hint.
That stopped CBO using the HASH_SJ hint.
Posting it here in the interests of others.