1

这可能是不可能的,但我希望看看是否有一种平易近人的方法来运行带有视图的表的在线替换。

对于分区等在线表重组,DBMS_REDEFINITION 效果很好。但我想用(物化)视图替换表,所以 DBMS_REDEFINITION 似乎不合适。

在重命名期间,我无需担心任何约束、依赖关系或变异 dml 等;我只想在用视图替换表时保持目标 SELECTable。下面是一个捏造的例子。

  CREATE TABLE SCI_FI_MOVIE (
  SCI_FI_MOVIE_ID NUMBER(10, 0)        NOT NULL PRIMARY KEY,
  NAME            VARCHAR2(100) UNIQUE NOT NULL,
  DIRECTOR        VARCHAR2(100)        NOT NULL,
  REVIEW_SCORE    NUMBER(1, 0) CHECK ( REVIEW_SCORE IN (1, 2, 3, 4, 5))
);

CREATE TABLE NO_SCORES_SCI_FI_MOVIE (
  SCI_FI_MOVIE_ID NUMBER(10, 0)        NOT NULL PRIMARY KEY,
  NAME            VARCHAR2(100) UNIQUE NOT NULL,
  DIRECTOR        VARCHAR2(100)        NOT NULL
);

CREATE MATERIALIZED VIEW KUBRICK_SABOTAGE
(SCI_FI_MOVIE_ID, NAME, DIRECTOR, REVIEW_SCORE)
REFRESH COMPLETE ON COMMIT
AS
  SELECT
    SCI_FI_MOVIE_ID,
    NAME,
    DIRECTOR,
    CASE WHEN DIRECTOR = 'KUBRICK'
      THEN 5
    ELSE 2 END AS REVIEW_SCORE
  FROM NO_SCORES_SCI_FI_MOVIE;

INSERT INTO SCI_FI_MOVIE VALUES (1, 'Apollo 13', 'HOWARD', 5);
INSERT INTO SCI_FI_MOVIE VALUES (2, '2001: A Space Odyssey', 'KUBRICK', 4);

INSERT INTO NO_SCORES_SCI_FI_MOVIE VALUES (1, 'Apollo 13', 'HOWARD');
INSERT INTO NO_SCORES_SCI_FI_MOVIE VALUES (2, '2001: A Space Odyssey', 'KUBRICK');

COMMIT;

-- THEN WHAT STEPS TO REPLACE TABLE WITH VIEW?

在此示例中,我希望以名为 SCI_FI_MOVIE 的 MV 和重命名为 SCI_FI_MOVIE_TEMP 的 TABLE SCI_FI_MOVIE 或任何待删除的内容结束。如果替换可以原子地完成,则在替换原始表之前不需要存在 MV

我想避免对对象名称解析的任何中断或妥协(CREATE PUBLIC SYNONYM然后重命名原始在这里不起作用)

有没有一种干净的无停机方式来做到这一点?
我可以根据需要随意禁用日志记录、只读等任何内容;唯一的目标是在字典切换期间防止“ORA-00942:表或视图不存在”。我使用的是 11gR2,但也欢迎使用 12c 解决方案。

非常感谢你的想法

4

1 回答 1

3

你不需要做在线重新定义或任何聪明的事情;您正在尝试做的是通过ON PREBUILT TABLE子句内置的:

ON PREBUILT TABLE 子句允许您将现有表注册为预初始化的物化视图。该子句对于在数据仓库环境中注册大型物化视图特别有用。该表必须与生成的物化视图具有相同的名称和相同的模式。

如果物化视图被删除,则先前存在的表将恢复为表的身份。

所以你可以这样做:

CREATE MATERIALIZED VIEW SCI_FI_MOVIE
(SCI_FI_MOVIE_ID, NAME, DIRECTOR, REVIEW_SCORE)
ON PREBUILT TABLE
REFRESH COMPLETE ON COMMIT
AS
  SELECT
    SCI_FI_MOVIE_ID,
    NAME,
    DIRECTOR,
    CAST(CASE WHEN DIRECTOR = 'KUBRICK'
      THEN 5
    ELSE 2 END AS NUMBER(1,0)) AS REVIEW_SCORE
  FROM NO_SCORES_SCI_FI_MOVIE;

Materialized view SCI_FI_MOVIE created.

CAST(... AS NUMBER(1,0))需要使生成的数据类型与基础表匹配。

该表在构建 MV 时被锁定(无论如何这几乎是即时的,因为没有数据收集或创建),因此在发生这种情况时对其进行的查询只会短暂阻塞。

该视图将具有原始表值:

select * from SCI_FI_MOVIE;

SCI_FI_MOVIE_ID NAME                           DIRECTOR   REVIEW_SCORE
--------------- ------------------------------ ---------- ------------
              1 Apollo 13                      HOWARD                5
              2 2001: A Space Odyssey          KUBRICK               4

...直到它被刷新,它(在这个例子中)将在下一次提交:

INSERT INTO NO_SCORES_SCI_FI_MOVIE VALUES (3, 'Star Wars', 'LUCAS');

1 row inserted.

COMMIT;

select * from SCI_FI_MOVIE;

SCI_FI_MOVIE_ID NAME                           DIRECTOR   REVIEW_SCORE
--------------- ------------------------------ ---------- ------------
              1 Apollo 13                      HOWARD                2
              2 2001: A Space Odyssey          KUBRICK               5
              3 Star Wars                      LUCAS                 2

对于普通(非物化视图),只要您可以创建公共同义词,您就可以进行一些改组来实现相同的目标:

CREATE TABLE SCI_FI_MOVIE_TMP_TAB AS SELECT * FROM SCI_FI_MOVIE;

CREATE VIEW SCI_FI_MOVIE_TMP_VIEW AS SELECT * FROM SCI_FI_MOVIE_TMP_TAB;

CREATE PUBLIC SYNONYM SCI_FI_MOVIE FOR SCI_FI_MOVIE_TMP_VIEW;

ALTER TABLE SCI_FI_MOVIE RENAME TO SCI_FI_MOVIE_OLD;

CREATE VIEW SCI_FI_MOVIE AS
  SELECT
    SCI_FI_MOVIE_ID,
    NAME,
    DIRECTOR,
    CAST(CASE WHEN DIRECTOR = 'KUBRICK'
      THEN 5
    ELSE 2 END AS NUMBER(1,0)) AS REVIEW_SCORE
  FROM NO_SCORES_SCI_FI_MOVIE;

DROP PUBLIC SYNONYM SCI_FI_MOVIE;

DROP VIEW SCI_FI_MOVIE_TMP_VIEW;

DROP TABLE SCI_FI_MOVIE_TMP_TAB;

DROP TABLE SCI_FI_MOVIE_OLD;

这依赖于Oracle 如何解析模式对象引用。当您重命名原始表时,它无法再在当前模式(命名空间)中找到具有该名称的对象,并寻找一个公共同义词,并愉快地使用它。当创建优先于公共同义词的视图时。

于 2016-06-17T18:03:26.343 回答