如何使一个架构依赖于其他架构

时间:2019-12-17 14:14:17

标签: sql database oracle

有一个问题,我找不到答案,有人可以帮助我吗?这是情况:

我有一个模式,那就是模板。

我想要这个模板有10个架构。

但是我希望每次更改模板架构的结构时(例如创建新列),都在与模板架构相关的所有架构中创建该列。

Oracle可以做到这一点吗?

3 个答案:

答案 0 :(得分:2)

正如其他人所说,默认情况下在Oracle中不可能这样做。但是,如果您使用的是最新版本(12.2和更高版本),并且不介意支付多租户选项,则可以考虑使用application containers。这会将您的架构在单个DB中交换为相同的架构,但在不同的PDB中。应用程序容器允许您在父PDB中定义架构(包括表,视图,触发器等),并使每个修改都传播到PDB(在需要时同步每个PDB)。

答案 1 :(得分:0)

  

但是我希望每次更改模板架构的结构时(例如创建新列),都在与模板架构相关的所有架构中创建该列。

     

Oracle可以做到这一点吗?

不,不是。您需要在每个用户(也称为架构)拥有的表中单独创建列。

答案 2 :(得分:0)

正如Justin Cave所建议的那样,您的问题实际上是在为Oracle分区尖叫。

如果您没有获得分区许可,仍然可以使用旧的(但免费的!)方法来创建分区视图。

通过这种方法,您可以保持历史表不变(即不要回去向其添加新列)。相反,您将创建一个包含每个历史表的分区视图(通过UNION ALL串联在一起)。视图定义可以为当年原始表中不存在的较新列提供值。

分区视图还具有以下优点:

  • 使多年报告变得容易
  • “分区修剪”-跳过给定查询中不感兴趣的表

以下是该方法的逐步介绍:

创建用于2019年和2020年数据的表

CREATE TABLE matt_data_2019 
  ( id NUMBER NOT NULL,
    creation_date DATE NOT NULL,
    data_column1 NUMBER,
    data_column2 VARCHAR2(200),
    CONSTRAINT matt_data_2019 PRIMARY KEY ( id ),
    CONSTRAINT matt_data_2019_c1 CHECK ( creation_date BETWEEN to_date('01-JAN-2019','DD-MON-YYYY') AND to_date('01-JAN-2020','DD-MON-YYYY') - interval '1' second )
 );

CREATE TABLE matt_data_2020 
  ( id NUMBER NOT NULL,
    creation_date DATE NOT NULL,
    data_column1 NUMBER,
    data_column2 VARCHAR2(200),
    data_column3 DATE,  -- This is new for 2020
    CONSTRAINT matt_data_2020 PRIMARY KEY ( id ),
    CONSTRAINT matt_data_2020_c1 CHECK ( creation_date BETWEEN to_date('01-JAN-2020','DD-MON-YYYY') AND to_date('01-JAN-2021','DD-MON-YYYY') - interval '1' second )
 );

请注意,2020年将增加一个新栏目,而2019年将不存在。

放入一些测试数据以确保准确的测试结果...

INSERT INTO matt_data_2019 ( id, creation_date, data_column1, data_column2 )
SELECT rownum id,
       to_date('01-JAN-2019','DD-MON-YYYY') + (dbms_random.value(0, 365*24*60*60-1) / (365*24*60*60)), -- Some random date in 2019
       dbms_random.value(0,1000),
       lpad('2019',200,'X')
FROM   dual
CONNECT BY rownum <= 100000;

INSERT INTO matt_data_2020 ( id, creation_date, data_column1, data_column2, data_column3 )
SELECT rownum id,
       to_date('01-JAN-2020','DD-MON-YYYY') + (dbms_random.value(0, 365*24*60*60-1) / (365*24*60*60)), -- Some random date in 2020
       dbms_random.value(0,1000),
       lpad('2020',200,'X'),
       to_date('01-JAN-2021','DD-MON-YYYY') + (dbms_random.value(0, 365*24*60*60-1) / (365*24*60*60)) -- Some random date in 2021
FROM   dual
CONNECT BY rownum <= 100000;

收集两个表的统计信息以获取准确的测试结果...

EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'MATT_DATA_2019');
EXEC DBMS_STATS.GATHER_TABLE_STATS(user,'MATT_DATA_2020');

创建一个包含所有表的视图。

每次创建新表时,您都需要修改此视图。

CREATE OR REPLACE VIEW matt_data_v AS
  SELECT 2019 source_year,
         id, 
         creation_date, 
         data_column1, 
         data_column2, 
         NULL data_column3   -- data_column3 did not exist in 2019
  FROM   matt_data_2019
  UNION ALL
  SELECT 2020 source_year,
         id, 
         creation_date, 
         data_column1, 
         data_column2, 
         data_column3   -- data_column3 did not exist in 2019
  FROM   matt_data_2020;

检查Oracle如何处理指定一年的查询

EXPLAIN PLAN SET STATEMENT_ID = 'MM' FOR SELECT * FROM MATT_DATA_V WHERE SOURCE_YEAR = 2020

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE','MM'));
Plan hash value: 393585474

---------------------------------------------------------------------------------------
| Id  | Operation            | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                |   110K|    15M|   620   (2)| 00:00:01 |
|   1 |  VIEW                | MATT_DATA_V    |   110K|    15M|   620   (2)| 00:00:01 |
|   2 |   UNION-ALL          |                |       |       |            |          |
|*  3 |    FILTER            |                |       |       |            |          |
|   4 |     TABLE ACCESS FULL| MATT_DATA_2019 | 71238 |  9530K|   596   (2)| 00:00:01 |
|   5 |    TABLE ACCESS FULL | MATT_DATA_2020 |   110K|    15M|   620   (2)| 00:00:01 |
---------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter(NULL IS NOT NULL)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

嗯,看起来就像甲骨文还在包括2019年的表格...

...但是不是。该NULL IS NOT NULL过滤条件将导致Oracle完全跳过2019表。

证明当我们要求提供2020年数据时,甲骨文正在跳过2019年的数据表...

alter session set statistics_level = ALL;

SELECT * FROM MATT_DATA_V WHERE SOURCE_YEAR = 2020;

-- Be sure to fetch entire result set (e.g., scroll to the end in SQL*Developer)

SELECT *
FROM   TABLE (DBMS_XPLAN.display_cursor (null, null,
                                         'ALLSTATS LAST'));
SQL_ID  1u3nwcnxs20jb, child number 0
-------------------------------------
SELECT * FROM MATT_DATA_V WHERE SOURCE_YEAR = 2020

Plan hash value: 393585474

-------------------------------------------------------------------------------------------------
| Id  | Operation            | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                |      1 |        |    100K|00:00:00.21 |    5417 |
|   1 |  VIEW                | MATT_DATA_V    |      1 |    110K|    100K|00:00:00.21 |    5417 |
|   2 |   UNION-ALL          |                |      1 |        |    100K|00:00:00.17 |    5417 |
|*  3 |    FILTER            |                |      1 |        |      0 |00:00:00.01 |       0 |
|   4 |     TABLE ACCESS FULL| MATT_DATA_2019 |      0 |  71238 |      0 |00:00:00.01 |       0 |
|   5 |    TABLE ACCESS FULL | MATT_DATA_2020 |      1 |    110K|    100K|00:00:00.09 |    5417 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter(NULL IS NOT NULL)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

以上结果显示了Oracle在我们不要求时如何跳过2019表。