2009年5月15日 星期五

物化视图快速刷新出错 ORA-12054

根据项目需求,需要创建一个增量更新的物化视图,语法如下:
CREATE MATERIALIZED VIEW LOG ON A WITH PRIMARY KEY ;
CREATE MATERIALIZED VIEW LOG ON B WITH PRIMARY KEY ;

CREATE MATERIALIZED VIEW MV_TEST
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT
A.COL1,B.COL1
FROM A,B
WHERE A.COL2 = B.COL2;
结果出现ORA-12054: 无法为实体化视图设置 ON COMMIT 刷新属性。
这个提示相当模糊,google到yangtingkun的blog,发现了查找详细原因的方法。
http://yangtingkun.itpub.net/post/468/13318

Oracle提供的DBMS_MVIEW.EXPLAIN_MVIEW过程可以帮助你快速定位问题的原因。下面通过一个例子来说明,如果通过这个过程来解决问题。
使用EXPLAIN_MVIEW 过程首先要建立MV_CAPABILITIES_TABLE表,建表的脚步是$ORACLE_HOME/rdbms/admin /utlxmv.sql。(EXPLAIN_MVIEW过程是两个过程的重载,一个输出到MV_CAPABILITIES_TABLE表,另一个以PL /SQL的VARRAY格式输出,为了简单起见,我们建立MV_CAPABILITIES_TABLE表)。
SQL> begin
2 dbms_mview.explain_mview('SELECT
3 A.COL1,B.COL1
4 FROM A,B
5 WHERE A.COL2 = B.COL2;');
6 end;
7 /
通过select capability_name, possible, msgtxt from mv_capabilities_table
where capability_name like 'REFRESH%';
可以查找出原因

经查,我这段sql错误原因是“物化视图日志没有基于rowid;物化视图引用的字段没有包含所有关联表的rowid”。
修改sql为:
CREATE MATERIALIZED VIEW LOG ON A WITH ROWID ;
CREATE MATERIALIZED VIEW LOG ON B WITH ROWID ;

CREATE MATERIALIZED VIEW MV_TEST
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT
A.COL1,B.COL1,A.ROWID AID,B.ROWID BID
FROM A,B
WHERE A.COL2 = B.COL2;
问题解决。

2009年5月7日 星期四

oracle9i的job在497天时不能执行

Oracle9i里面有一个BUG,当计数器到497天时,刚好达到它的最大值,再计数就会变成-1,继续计数就变成0了,然后计数器将不再跑了。
1. Clear description of the problem encountered:
slgcsf() / slgcs() on Solaris will stop incrementing after
497 days 2 hrs 28 mins (approx) machine uptime.

2. Pertinent configuration information
No special configuration other than long machine uptime. .

3. Indication of the frequency and predictability of the problem
100% but only after 497 days.

4. Sequence of events leading to the problem
If the gethrtime() OS call returns a value > 42949672950000000
nanoseconds then slgcs() stays at 0xffffffff. This can
cause some problems in parts of the code which rely on
slgcs() to keep moving.
eg: In kkjssrh() does "now = slgcs(&se)" and compares that
to a previous timestamp. After 497 days uptime slgcs()
keeps returning 0xffffffff so "now - kkjlsrt" will
always return 0. .

5. Technical impact on the customer. Include persistent after effects.
In this case DBMS JOBS stopped running after 497 days uptime.
Other symptoms could occur in various places in the code.

Oracle最后声称:
fix made it into 9.2.0.6 patchset.

如果不能进行升级的话,重启数据库可以解决这个问题。

2009年5月6日 星期三

winxp下ORACLE9I创建数据库出现ORA-01503 ORA-00058

今天在本机创建一个9i的数据库
操作系统:windows xp pro sp2
数据库 :oracle 9.2.0.1.0

在创建过程中出现ORA-01503 ORA-00058错误,提示DB_BLOCK_SIZE不正确。
google之:

ORA-00058 DB_BLOCK_SIZE must be string to mount this database (not string)


Cause: The value of the DB_BLOCK_SIZE initialization parameter used to start this database does not match the value used when that database was created. Potential reasons for this mismatch are:

mounting the wrong database

using the wrong initialization parameter file

the value of the DB_BLOCK_SIZE parameter was changed

Action: For one of the above causes, either:

mount the correct database

use the correct initialization parameter file

correct the value of the DB_BLOCK_SIZE parameter

根据提示修改DB_BLOCK_SIZE,问题解决。

2009年5月5日 星期二

使用 PDI 和 Oracle CDC 来实现Oracle 数据库向其他数据库的数据同步

使用 PDI 和 Oracle CDC 来实现Oracle 数据库向其他数据库的数据同步

本文讲述如何利用 Oracle CDC 和 PDI 来实现 Oracle 数据库向其他数据源的数据同步。

第一节 介绍Oracle CDC,如果您熟悉 Oracle CDC 可以跳过该节。
第二节 说明如何配置 PDI 里的 Oracle CDC 输入和 Oracle CDC 输出 插件。


第一节 Oracle CDC 介绍(本节主要内容摘自 OWB 用户手册)

发布和订阅模型
大多数 CDC 系统都需有人来完成数据的捕获和发布,这个人就是发布者。同时也有多个应用程序或人来访问发布的数据,这些应用程序或个人就是订阅者。 CDC 提供了 PL/SQL 包来完成发布和订阅任务。

发布者:
发布者通常是数据库的DBA, 他创建和维护包括了 CDC 系统的模式对象,发布者要和两个数据库进行交互
源数据库(source database):
即生产系统数据库,里面包含了需要发布的数据,相关的表称为源表。
中间数据库(staging database)
中间数据库是实际完成数据捕获的数据。依赖于发布者使用的捕获方式,中间数据库可以是源数据库也可以不是源数据库。中间数据库中保存下面的 CDC 对象。
变更表(change table):
变更表是一个关系表,包含了源表中变化的数据。对于发布者而言,变更表就是数据发布。
变更集(change set)
变更集是一组变更的数据,它们用来保证事务的一致性,包含一个或多个变更表。
变更源(change source)
变更源是对源数据库的一种逻辑表示,它包括一个或多个变更集。
发布者需要完成的任务包括:
决定哪些源数据库和表是订阅者关心的,以及要使用的 CDC 的模式(同步或异步)
使用Oracle 提供的包 DBMS_CDC_PUBLISH 从源表中建立 CDC 系统
通过 GRANT 和 REVOKE 这样的SQL 语句来管理订阅者访问变更表的权限(不过访问者不会直接访问变更表,而是访问视图)。
订阅者:
订阅者是已经发布的并更数据的用户,订阅者需要完成下面的任务:
1. 使用Oracle 提供的包 DBMS_CDC_SUBSCRIBE 来完成
创建订阅:
通知CDC准备接收变更的数据:
通知CDC 完成一组变更数据:
2. 使用 SELECT 语句从订阅者视图中抽取变化的数据。


变更源和数据捕获模型
同步模式:
同步模式使用源数据库触发器来捕获变更的数据。这种方式是实时的没有延迟。当 DML 操作提交后,变更表中就产生了变更数据。
同步模式会给源数据库增加负载,但和数据表比较的方式相比,同步模式可以减少系统负载。
同步变更源 SYNC_SOURCE 是唯一的、预定义的,它代表了源数据库。不能更改和删除。
在同步模式下,变更表必须存在于源数据库本地。

异步模式:
异步模式使用数据库的重做日志(redo log)文件,在源数据库发生变更以后,才进行数据捕获。异步模式依赖于源数据库的补充日志(supplemental logging)的级别。补充日志会给源数据库增添了负载,所以要小心使用异步CDC 模式。
有两种方式来捕获异步变更数据,分别是HotLog和AutoLog:

HotLog:
HotLog是从源数据库的重做日志文件中获得变更的数据。这种方式会有一段时间延迟。
HotLog变更源 HOTLOG_SOURCE 也是唯一的、预定义的,它代表了源数据库的重做日志文件。不能更改和删除。
在HotLog模式下,变更表必须存在于源数据库本地。

AutoLog:
AutoLog是从日志转移服务(Log transport services)管理的一组重做日志文件中获得变更数据。日志转移服务将重做日志文件自动地从源数据库转移到中间数据库。通过使用数据库初始化参数,发布者可以配置日志转移服务使其能够自动的从源数据库将重做日志文件转移到中间数据库。在中间数据库中,当来了新的重做日志文件,就可以获取到新的变更数据。因此延迟程度取决于重做日志文件的转移频率。
没有预定义的AutoLog 变更源。发布者提供源数据库信息来创建一个AutoLog 数据源。
在HotLog模式下,变更表可以保存在源数据库本地或远程,一般都是保存在远程。


变更集:
一个变更集是一组变更的数据,它作为一个整体来管理,可以保证事务的一致性。一个变更集只属于一个变更源。一个变更源可以包括多个变更集。从概念上将,变更集和变更源的模式应该相同,也就是说,AutoLog模式的变更集是属于AutoLog变更源的。
当一个发布者将两个或更多的变更表放在同一个变更集中,订阅者可以连接变更集里表而且要保证事务的一致性。三种模式的变更集:
同步:
在预定义好的变更源 SYNC_SOURCE 中,发布者可以定义新的变更集,也可以使用预定义的变更集SYNC_SET。预定义的变更集SYNC_SET不能更新和删除。
异步HotLog:
发布者要在预定义的数据源 HOTLOG_SOURCE 中定义新的数据集。
异步AutoLog
发布者要在用户定义的数据源中定义新的数据集。

总结:
模式 变更源 代表的源数据库 相关的变更集
同步 预定义 SYNC_SOURCE 本地 预定义SYNC_SET 和发布者定义
异步HotLog 预定义 HOTLOG_SOURCE 本地 发布者定义
异步AutoLog Publisher-defined 远程或本地 发布者定义


变更表:
变更表中包含了源表中变更的数据。变更表中的数据分为两部分,一部分是变更数据本身,另一部分是变更表的必要的控制数据。
发布者可以指定源表中的哪些列可以包含在变更表中。一般,发布者会将源表的主键列和订阅者感兴趣的列加入到变更表中。
变更表中还包括了必要的和可选的控制列,可选的控制列由发布者在创建变更表时指定。控制列由 CDC 来管理。

列 数据类型 模式 可选 描述
----------------------------------------------------------------------
OPERATION$ CHAR(2) 所有 否 I: INSERT 操作
UO: UPDATE 操作前的源表镜像
UU: UPDATE 操作前的源表镜像
UN: UPDATE 操作后的源表镜像
D: DELETE 操作

CSCN$ NUMBER 所有 否 事务的提交 SCN 号(SYSTEM CHANGE NUMBER)
RSID$ NUMBER 所有 是 事务内的唯一操作顺序ID,不能跨事务, 必须和CSCN$一起使用
SOURCE_COLMAP$ RAW(128) 同步 是 源表中更新的列的位掩码.
TARGET_COLMAP$ RAW(128) 所有 是 变更表中更新的列的位掩码.
COMMIT_TIMESTAMP$ DATE 所有 否 事务提交时间.
TIMESTAMP$ DATE 所有 是 源数据库中操作发生的时间.
USERNAME$ VARCHAR2(30) 所有 是 源数据库中完成该操作的用户名.
ROW_ID$ ROW_ID 所有 是 源表中行的ROW ID.
XIDUSN$ NUMBER 异步 否 事务 ID undo 片段号.
XIDSLT$ NUMBER 异步 否 事务 ID 槽号.
XIDSEQ$ NUMBER 异步 否 事务 ID 顺序号.
SYS_NC_OID$ RAW(16) 异步 是 对象 ID.

说明 1. OPERATION$ 是 CHAR(2) 类型,在查询 I 操作和 D操作时,要注意查询条件是 OPERATION$='I ' 和 OPERATION$='D '
2. 如果要按照数据变更发生的顺序排序,则排序子语句是 ORDER BY CSCN$, RSID$


理解 TARGET_COLMAP$和 SOURCE_COLMAP$

TARGET_COLMAP$ 和 SOURCE_COLMAP$ 用于表示那一列发生了变化. TARGET_COLMAP$ 表示变更表中的哪一列发生了变化. SOURCE_COLMAP$ (只使用在同步变更表中) 表示在源表中哪一列发生了变化.
因为 TARGET_COLMAP$ 和 SOURCE_COLMAP$ 的数据类型是 RAW(128), 每一个列可以保存128字节的二进制信息.


下面详细说一下 同步CDC 的发布和订阅步骤,异步CDC 的发布和订阅步骤请参考 OWB 用户手册

同步CDC 的发布步骤:

第一步 DBA: 设置 AVA_POOL_SIZE 参数
java_pool_size = 50000000
第二步 DBA: 创建发布者并授权 (如果DBA 直接作为发布者,该步骤可以省略)
CREATE USER cdcpub IDENTIFIED BY cdcpub DEFAULT TABLESPACE ts_cdcpub QUOTA UNLIMITED ON SYSTEM QUOTA UNLIMITED ON SYSAUX;
GRANT CREATE SESSION TO cdcpub;
GRANT CREATE TABLE TO cdcpub;
GRANT CREATE TABLESPACE TO cdcpub;
GRANT UNLIMITED TABLESPACE TO cdcpub;
GRANT SELECT_CATALOG_ROLE TO cdcpub;
GRANT EXECUTE_CATALOG_ROLE TO cdcpub;
GRANT CONNECT, RESOURCE TO cdcpub;

第三步 cdcpub: 创建变更集 (如果使用缺省变更集 SYNC_SET 该步骤可以省略)
BEGIN
DBMS_CDC_PUBLISH.CREATE_CHANGE_SET(
change_set_name => 'CHICAGO_DAILY',
description => 'Change set for job history info',
change_source_name => 'SYNC_SOURCE');
END;
/

第四步 cdcpub: 创建变更表
BEGIN
DBMS_CDC_PUBLISH.CREATE_CHANGE_TABLE(

owner => 'cdcpub',
change_table_name => 'jobhist_ct',
change_set_name => 'CHICAGO_DAILY',
source_schema => 'HR',
source_table => 'JOB_HISTORY',
column_type_list => 'EMPLOYEE_ID NUMBER(6),START_DATE DATE,
END_DATE DATE,JOB_ID VARCHAR2(10),
DEPARTMENT_ID NUMBER(4)',
capture_values => 'both',
rs_id => 'y',
row_id => 'n',
user_id => 'n',
timestamp => 'n',
object_id => 'n',
source_colmap => 'y',
target_colmap => 'y',
options_string => 'TABLESPACE TS_CHICAGO_DAILY');
END;
/


第五步 cdcpub: 给订阅者授权
GRANT SELECT ON cdcpub.jobhist_ct TO subscriber1;


同步 CDC 的订阅步骤

第一步: 找到订阅者可以访问的已发布的源表
SELECT * FROM ALL_SOURCE_TABLES;

SOURCE_SCHEMA_NAME SOURCE_TABLE_NAME
------------------------------ ------------------------------
HR JOB_HISTORY

第二步:找到订阅者可以访问的变更集名称和列名
SELECT UNIQUE CHANGE_SET_NAME, COLUMN_NAME, PUB_ID
FROM ALL_PUBLISHED_COLUMNS
WHERE SOURCE_SCHEMA_NAME ='HR' AND SOURCE_TABLE_NAME = 'JOB_HISTORY';

CHANGE_SET_NAME COLUMN_NAME PUB_ID
---------------- ------------------ ------------
CHICAGO_DAILY DEPARTMENT_ID 34883
CHICAGO_DAILY EMPLOYEE_ID 34883
CHICAGO_DAILY END_DATE 34883
CHICAGO_DAILY JOB_ID 34883
CHICAGO_DAILY START_DATE 34883

第三步:创建一个订阅
BEGIN
DBMS_CDC_SUBSCRIBE.CREATE_SUBSCRIPTION(
change_set_name => 'CHICAGO_DAILY',
description => 'Change data for JOB_HISTORY',
subscription_name => 'JOBHIST_SUB');
END;
/

订阅名称是 "JOBHIST_SUB"

第四步:订阅源表中的哪些列
BEGIN
DBMS_CDC_SUBSCRIBE.SUBSCRIBE(
subscription_name => 'JOBHIST_SUB',
source_schema => 'HR',
source_table => 'JOB_HISTORY',
column_list => 'EMPLOYEE_ID, START_DATE, END_DATE, JOB_ID',
subscriber_view => 'JOBHIST_VIEW');
END;
/

订阅视图名称是 "JOBHIST_VIEW"

第五步:激活订阅
BEGIN
DBMS_CDC_SUBSCRIBE.ACTIVATE_SUBSCRIPTION(
subscription_name => 'JOBHIST_SUB');
END;
/

第六步:获得下一组变更数据
BEGIN
DBMS_CDC_SUBSCRIBE.EXTEND_WINDOW(
subscription_name => 'JOBHIST_SUB');
END;
/

第七步:读取和查询订阅视图中的内容
SELECT EMPLOYEE_ID, START_DATE, END_DATE FROM JOBHIST_VIEW;
EMPLOYEE_ID START_DAT END_DATE
----------- --------- ---------
176 24-MAR-98 31-DEC-98
180 24-MAR-98 31-DEC-98
190 01-JAN-99 31-DEC-99
200 01-JAN-99 31-DEC-99

第八步:清除当前的变更数据
BEGIN
DBMS_CDC_SUBSCRIBE.PURGE_WINDOW(
subscription_name => 'JOBHIST_SUB');
END;
/

第九步:重复第六步到第八步
第十步:删除订阅
BEGIN
DBMS_CDC_SUBSCRIBE.DROP_SUBSCRIPTION(
subscription_name => 'JOBHIST_SUB');
END;
/


第二节 PDI 中 Oracle CDC 输入和 Oracle CDC 输出插件的配置

1. 前提

(1) Oracle 数据库的发布者已经完成了数据的发布,(即上述发布步骤的所有步骤)。
(2) Oracle 数据库的订阅者已经完成一个订阅,并激活了该订阅,(即上述订阅步骤的第一步到第五步)。


2. 配置
Oracle CDC 输入插件:只要配置三个选项
(1)数据库连接:注意要以 订阅者 或 DBA 身份连接。
(2)订阅名称:上述订阅步骤第三步中设置的 subscription_name。
(3)订阅视图名称: 上述订阅步骤第四步中设置的 subscriber_view。

Oracle CDC 输出插件:
(1)数据库连接:选择一个要输出的数据库连接。
(2)目标表名称:选择数据库中的一个表。
(3)关键字:目标表里的关键字。

3. 部署

将定义好的转换保存成 ktr 文件,或保存在资源库中。
使用操作系统的调度(linux:corn,windows:计划任务)或 kettle 的作业调度,来定时运行命令(如 pan /file:C:xxx.ktr)。

author:PDI_CHINA@LIVE.CN

Oracle长时间操作会话(六秒以上)查询

SELECT T.USERNAME,
T.OPNAME,
T.TARGET,
T.SOFAR,
T.TOTALWORK,
T.TIME_REMAINING,
T.ELAPSED_SECONDS,
T.MESSAGE
FROM SYS.V_$SESSION_LONGOPS T
WHERE T.SOFAR <> T.TOTALWORK

2009年5月4日 星期一

Oracle OFA结构

OFA总体结构分两层,一层是software-oracle software,一层是Files(database)
software目录结构
oracle_base/--------------------------------------起名oracle最多
/product------------------------------------很多安装省略
/release_number--------------------这个一般作为Oracle_home
/bin
/dbs--------------------------------9i spfile默认位置,8i一般同时链接到/admin/pfile
/rdbms
/sqlplus
/admin
/inst_name-----------------不同的实例这个目录可以多个
/pfile
/dump....

Files目录结构
oradata/
db01/------------------------------------database db01
system01.dbf
confrol01.ctl
redo0101.log
db02/------------------------------------database db02



OFA只是oracle公司推荐的一种在服务器上安装oracle数据库系统的目录规划,以便于做维护。要点就是,整个数据库系统可以分为软件产品、每个实例的管理配置文件、数据库文件三部分,分别放在不同的目录下。

OFA的方法包括以下三条原则:
一:创建一个有续的操作系统目录结构,在此目录下存储文件可以存储在任何一个磁盘里.
命名可能存放oracle的所有设备,在以设备为单位来指定设备的时候可以用同配符或者类似的方法.
在每个设备的同一级目录下明确的创建一个用于存储oracle数据的目录.
二:根据不同的用途和特征,把段(数据对象)分成组分三到不同的表空间中.
根据碎块特征,把不同组的数据对象分散到不同表空间中(例如,不要将数据段和回滚段放在一起).
根据对磁盘资源的竞争使用状态,把不同组的段分散到不同的表空间中(例如,不要把数据和索引放在一起).
根据所代表对象的不同行为特征,把不同组的段分散到不同的表空间中 (例如,不要把需要每日备份一次的表和需要每年备份依次的表放在同一个表空间中).
三 把数据库足见分散到不同的磁盘空间中,使数据库的可靠性和运行效率最大化.注意在RAID环境下不要考虑把数据文件分散到在多个控制器组中.
数据库控制文件至少要在三个不容物理磁盘阵列中分别有三个可用的副本.
把那些存储了抢夺磁盘资源的数据的表空间分散在不同的物理磁盘上(还应该考虑到磁盘控制器的使用情况).