我们有一个高度(可能超过?)规范化的表来跟踪版本化值。它只是插入,没有更新。
示例数据:
"ID" "Version" "Value"
1 0 "A_1"
2 0 "B_1"
1 1 "A_2"
3 0 "C_1"
我们经常运行查询以仅为每个ID提取最新值。当我们达到数百万行时,我们开始遇到性能问题。我已经能够使用物化视图对原型进行原型设计,但是无法以自动刷新“ON COMMIT”的方式创建它们
到目前为止我得到的是(下面修订)
CREATE MATERIALIZED VIEW TABLE_LATEST
BUILD IMMEDIATE
REFRESH FAST
ON COMMIT AS
SELECT T.ID
,T.LAST_VERSION
FROM (
SELECT ID
,MAX(VERSION) OVER (PARTITION BY ID) LAST_VERSION
FROM TABLE
) T
GROUP BY T.ID, T.LAST_VERSION;
由于反馈,现在已经修订了:
CREATE MATERIALIZED VIEW TABLE_LATEST
BUILD IMMEDIATE
REFRESH FAST
ON COMMIT AS
SELECT ID
,MAX(VERSION)
FROM TABLE
GROUP BY T.ID;
哪个失败了:
ORA-12033:无法使用物化视图登录中的过滤列 “模式”。 “TABLE”
*Cause: The materialized view log either did not have filter columns logged, or the timestamp associated with the filter columns was more recent than the last refresh time. *Action: A complete refresh is required before the next fast refresh. Add filter columns to the materialized view log, if required.
如果我将Refresh
更改为Force
并删除On Commit
,它将“有效”。我不知道这是否属于物化视图的“无分析”规则,或者我是否首先错误地创建了日志?
CREATE MATERIALIZED VIEW LOG ON TABLE
LOGGING
WITH SEQUENCE, ROWID, (VALUE)
INCLUDING NEW VALUES;
表架构:
CREATE TABLE "TABLE"
(
ID NUMBER(10, 0) NOT NULL
, VERSION NUMBER(10, 0) NOT NULL
, VALUE VARCHAR2(4000 CHAR)
, CONSTRAINT MASTERRECORDFIELDVALUES_PK PRIMARY KEY
(
ID
, VERSION
)
USING INDEX
(
CREATE UNIQUE INDEX TABLE_PK ON TABLE(ID ASC, VERSION ASC)
LOGGING
...
)
ENABLE
)
LOGGING
我是否走在正确的轨道上?是否有更好的预先计算最新版本的方法?或者我只需要获取Log&查看设置中的设置?
答案 0 :(得分:1)
我很抱歉,但我不能马上回答你的问题。一个原因可能是使用分析功能,而这些功能并不能很好地支持MV。要分析问题,您需要查看物化视图的功能。
DECLARE
-- Local variables here
--
v_sql VARCHAR2(32000) := 'SELECT T.ID
,T.LAST_VERSION
FROM (SELECT ID
,MAX(VERSION) OVER (PARTITION BY ID) LAST_VERSION
FROM TABLE) T
GROUP BY T.ID
,T.LAST_VERSION';
v_msg_arrray SYS.EXPLAINMVARRAYTYPE;
msg SYS.ExplainMVMessage;
BEGIN
-- Test statements here
dbms_mview.explain_mview(mv => v_sql, msg_array => v_msg_arrray);
FOR i IN v_msg_arrray.FIRST..v_msg_arrray.LAST LOOP
msg := v_msg_arrray(i);
DBMS_OUTPUT.put_line('MVOWNER:' || msg.MVOWNER);
DBMS_OUTPUT.put_line('MVNAME:' || msg.MVNAME);
DBMS_OUTPUT.put_line('CAPABILITY_NAME:' || msg.CAPABILITY_NAME);
DBMS_OUTPUT.put_line('POSSIBLE:' || msg.POSSIBLE);
DBMS_OUTPUT.put_line('RELATED_TEXT:' || msg.RELATED_TEXT);
DBMS_OUTPUT.put_line('RELATED_NUM:' || msg.RELATED_NUM);
DBMS_OUTPUT.put_line('MSGNO:' || msg.MSGNO);
DBMS_OUTPUT.put_line('MSGTXT:' || msg.MSGTXT);
DBMS_OUTPUT.put_line('SEQ:' || msg.SEQ);
DBMS_OUTPUT.put_line('----------------------------------------');
END LOOP;
END;
BTW:您可以更简单地编写查询:
SELECT t.id,
MAX(t.version) AS last_version
FROM table t
GROUP BY t.id;
答案 1 :(得分:1)
如果您不需要与最新版本相关联的值,那么您可以这样做:
CREATE MATERIALIZED VIEW LOG ON t1
LOGGING
WITH SEQUENCE, ROWID, (val)
INCLUDING NEW VALUES;
create materialized view t1_latest
refresh fast on commit
as
select id,
max(version) latest_version
from t1
group by id;
可以找到over at Oracle LiveSQL的测试用例。
否则,您需要创建三个单独的MV(因为您无法在提交物化视图上快速刷新,包括保持第一个/最后一个的密集) - 按照http://www.sqlsnippets.com/en/topic-12926.html - 如此:
主表上的物化视图日志:
CREATE MATERIALIZED VIEW LOG ON t1
LOGGING
WITH SEQUENCE, ROWID, (val)
INCLUDING NEW VALUES;
第一个物化视图:
create materialized view t1_sub_mv1
refresh fast on commit
as
select id,
max(version) latest_version,
count(version) cnt_version,
count(*) cnt_all
from t1
group by id;
第一个物化视图的物化视图日志:
create materialized view log on t1_sub_mv1
with rowid, sequence (id, latest_version, cnt_version, cnt_all)
including new values;
第二个物化视图:
create materialized view t1_sub_mv2
refresh fast on commit
as
select id,
version,
max(val) max_val_per_id_version,
count(*) cnt_all
from t1
group by id,
version;
第一个物化视图的物化视图日志:
create materialized view log on t1_sub_mv2
with rowid, sequence (id, max_val_per_id_version, cnt_all)
including new values;
第三个也是最后一个具体化视图:
create materialized view t1_main_mv
refresh fast on commit
as
select mv1.id,
mv1.latest_version,
mv2.max_val_per_id_version val_of_latest_version,
mv1.rowid mv1_rowid,
mv2.rowid mv2_rowid
from t1_sub_mv1 mv1,
t1_sub_mv2 mv2
where mv1.id = mv2.id
and mv1.latest_version = mv2.version;
可以找到over at Oracle LiveSQL的支持测试用例。