在做exp的时候,我们可以做owner级的导出,导出该用户下的所有对象。owner级的导出,会导出所有的表,不太容易排除单独的一些表;而如果做table级的导出,就必须列出所有的table,且当数据库有增加新table的时候,也得把新增的table加到exp的列表中。
今天收到一个客户的要求,做owner级别的导出,但是需要排除几张大表。该需要做成定时的脚本每天执行。
其实,如果在10g中用数据泵,这个exclude很方便处理,但是在9i中,用什么方法才能把某些表单独排除呢?原来我们可以用FGAC来实现。
一、在这里,我们假设我们需要对用户mytest做owner级导出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
SQL> create user mytest identified by mytest default tablespace users; 用户已创建。 SQL> grant connect,resource to mytest; 授权成功。 SQL> SQL> conn mytest/mytest 已连接。 SQL> SQL> SQL> create table t1 as select * from dual; 表已创建。 SQL> SQL> SQL> create table t2 as select * from all_objects; 表已创建。 SQL> select table_name from user_tables; TABLE_NAME ------------------------------ T1 T2 SQL> |
二、新建一个用户用于做exp的导出,新建该用户的目的是:该用户只是用来做exp导出,而不修改原来的dba用户或者application用户来做exp导出:
1 2 3 4 5 6 7 8 9 |
SQL> create user expuser identified by expuser default tablespace users; 用户已创建。 SQL> grant connect,resource,dba to expuser; 授权成功。 SQL> |
三、建立exclude_table 函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
SQL> conn expuser/expuser 已连接。 SQL> CREATE or REPLACE FUNCTION exclude_table(obj_schema VARCHAR2, 2 obj_name VARCHAR2) 3 RETURN VARCHAR2 IS 4 d_predicate VARCHAR2(2000); 5 BEGIN 6 if sys_context('USERENV', 'SESSION_USER') = 'EXPUSER' THEN 7 d_predicate := '1=2'; 8 else 9 d_predicate := ''; 10 end if; 11 RETURN d_predicate; 12 END exclude_table; 13 / 函数已创建。 SQL> |
这个函数用来控制用户对某个表的访问,FGAC大致的功能是利用dbsm_rls部署一些策略(policy),这些策略会调用一些函数,比如上面我定义的那个exclude_table函数,利用函数,来使得普通执行的sql后面加上谓词。
比如,某sql是:
1 |
select table_name from dba_tables; |
被细粒度权限控制之后,这个sql语句会自动在后面加上where的谓词做过滤,变成类似:
1 |
select table_name from dba_tables where owner='MYUSER'; |
因此,当被细粒度权限控制之后,就算执行select table_name from dba_tables;也只能出现owner=’MYUSER’的表。
回到上面的exclude_table函数,大致的意思就是当操作的用户是EXPUSER的时候,就在操作的语句后面加1=2,我们知道1=2为非真,因此能select出来的结果肯定是0行。因此,这样就类似的实现了我们对某些表做exp的时候,不导出数据的目的。
好,我们继续把这个函数的功能加到mytest用户下的t1表上。我们用dbms_rls.add_policy来实现,我们先看一下这个过程的参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
PROCEDURE ADD_POLICY 参数名称 类型 输入/输出默认值? ------------------------------ ----------------------- ------ -------- OBJECT_SCHEMA VARCHAR2 IN DEFAULT OBJECT_NAME VARCHAR2 IN POLICY_NAME VARCHAR2 IN FUNCTION_SCHEMA VARCHAR2 IN DEFAULT POLICY_FUNCTION VARCHAR2 IN STATEMENT_TYPES VARCHAR2 IN DEFAULT UPDATE_CHECK BOOLEAN IN DEFAULT ENABLE BOOLEAN IN DEFAULT STATIC_POLICY BOOLEAN IN DEFAULT POLICY_TYPE BINARY_INTEGER IN DEFAULT LONG_PREDICATE BOOLEAN IN DEFAULT SEC_RELEVANT_COLS VARCHAR2 IN DEFAULT SEC_RELEVANT_COLS_OPT BINARY_INTEGER IN DEFAULT 几个主要字段的解释: object_schema:用来做细粒度访问控制对象所对应的用户,如果为空则默认是当前用户。 object_name:用来做细粒度访问控制对象(可以是表,或视图或同义词) policy_name:策略名,可自定义。但是如果对同一表或者视图,策略名必须唯一。但是如果是不同用户下的同一个表或者视图,可以用相同的策略名。 function_schema:自定义函数的用户,该用户应该有权限能调用之前我们建立的那个函数。如果为空,则默认是当前用户。 policy_function:函数名,即之前我们自己定义谓词的函数,如果函数定义在包里面,则这里也需写上包的名字。 statement_types:操作的类型,如select,insert,update或delete,如果为空,则默认是所有类型的操作。 |
因此对于排除mytest用户下的t1表,我们可以执行:
1 2 3 4 5 6 |
SQL> exec dbms_rls.add_policy(OBJECT_SCHEMA=>'MYTEST',OBJECT_NAME=>'T1',POLICY_NAME=>'POL_T1',FUNCTION_SCHEMA=>'EXPUSER' ,POLICY_FUNCTION=>'EXCLUDE_TABLE'); PL/SQL 过程已成功完成。 SQL> |
上述的结果可以用这个sql去检查:
1 2 3 4 5 6 7 8 |
SQL> select OBJECT_OWNER,OBJECT_NAME,POLICY_GROUP,POLICY_NAME,PF_OWNER,FUNCTION from dba_policies 2 where PF_OWNER='EXPUSER'; OBJECT_OWN OBJECT_NAM POLICY_GROUP POLICY_NAM PF_OWNER FUNCTION ---------- ---------- ------------------------------ ---------- ---------- ------------------------------ MYTEST T1 SYS_DEFAULT POL_T1 EXPUSER EXCLUDE_TABLE SQL> |
四、好,我们现在来测试owner级导出:
1、我们先测试一下select操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
SQL> conn system/manager 已连接。 SQL> select * from mytest.t1; D - X SQL> SQL> conn expuser/expuser 已连接。 SQL> select * from mytest.t1; 未选定行 SQL> |
这里的区别已经很明显的看出来了。
2、最后我们来实现我们的需求,按照owner级的导出,却排除t1表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
C:\>exp expuser/expuser owner=mytest file=mytest.dmp log=mytest.log; Export: Release 10.2.0.1.0 - Production on 星期五 1月 7 22:25:34 2011 Copyright (c) 1982, 2005, Oracle. All rights reserved. 连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production With the Partitioning, OLAP and Data Mining options 已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集 即将导出指定的用户... . 正在导出 pre-schema 过程对象和操作 . 正在导出用户 MYTEST 的外部函数库名 . 导出 PUBLIC 类型同义词 . 正在导出专用类型同义词 . 正在导出用户 MYTEST 的对象类型定义 即将导出 MYTEST 的对象... . 正在导出数据库链接 . 正在导出序号 . 正在导出簇定义 . 即将导出 MYTEST 的表通过常规路径... EXP-00079: 表 "T1" 中的数据是被保护的。常规路径只能导出部分表。 . . 正在导出表 T1导出了 0 行 EXP-00091: 正在导出有问题的统计信息。 . . 正在导出表 T2导出了 38250 行 . 正在导出同义词 . 正在导出视图 . 正在导出存储过程 . 正在导出运算符 . 正在导出引用完整性约束条件 . 正在导出触发器 . 正在导出索引类型 . 正在导出位图, 功能性索引和可扩展索引 . 正在导出后期表活动 . 正在导出实体化视图 . 正在导出快照日志 . 正在导出作业队列 . 正在导出刷新组和子组 . 正在导出维 . 正在导出 post-schema 过程对象和操作 . 正在导出统计信息 导出成功终止, 但出现警告。 C:\> |
我们看到t1表导出了0行(但是表结构还是被导出的)。
五、取消FGAC。
取消很容易,执行执行dbms_rls中的drop_policy即可:
1 2 3 4 5 |
SQL> exec dbms_rls.drop_policy(OBJECT_SCHEMA=>'MYTEST',OBJECT_NAME=>'T1',POLICY_NAME=>'POL_T1'); PL/SQL 过程已成功完成。 SQL> |
5条评论
强!
学习了
不错不错
我看你的exclude_table 函数,并没有对表名T1,T2进行判断,你怎么做到只导出来T2数据,不导出T1数据呢…
re magscott:exclude_table是我自己写的一个过程,是对session的user进行判断。而对表的判断是在FGAC中实现的,是在dbms_rls中控制的,导出是导除了T1外的所有表。如果多个表需要排除,需要添加多个policy。