Database Link与GLOBAL_NAMES参数

Posted by 老熊 on 7月 20th, 2008

当GLOBAL_NAMES参数设置为TRUE时,使用DATABASE LINK时,DATABASE LINK的名称必须与被连接库的GLOBAL_NAME一致。下面做一个测试,在测试中,创建数据库链接的库为XJ(WINDOWS 2003 ORACLE 10g 10.2.0.1),被链接的库为DMDB(LINUX AS5 ORACLE 10g 10.2.0.1 RAC)

首先查看DMDB的相关配置:

SQL> show parameter global_names

NAME                                 TYPE        VALUE
------------------------------------ ----------- ---------
global_names                         boolean     FALSE
SQL> select * from global_name;;

GLOBAL_NAME
----------------------------------------------------------
DMDB

可以看到这个被链接的库其global_names参数为FALSE。

要创建数据库链接的库的配置:

SQL> show parameter global_names

NAME                                 TYPE        VALUE
------------------------------------ ----------- -------
global_names                         boolean     FALSE
SQL> select * from global_name;

GLOBAL_NAME
--------------------------------------------------------
XJ

然后做下面的操作:

SQL> create database link test_link connect to test identified by test using ‘DMDB’;

数据库链接已创建。

SQL> select * from dual@test_link;

D
-
X

可以看到数据库链接工作正常。

在DMDB库上将global_names设为TRUE:

SQL> alter system set global_names=true;

系统已更改。

在XJ库上再次查询,并新建一个DATABASE LINK再进行查询:

SQL> select * from dual@test_link;

D
-
X

SQL> create database link test_link2 connect to test identified by test using ‘D
MDB’;

数据库链接已创建。

SQL> select * from dual@test_link2;

D
-
X

此时可以看数据库链接工作正常。我们再将XJ库的global_names参数设置为TRUE:

SQL> alter system set global_names=true;

系统已更改。

SQL> select * from dual@test_link2;
select * from dual@test_link2
                   *
第 1 行出现错误:
ORA-02085: 数据库链接 TEST_LINK2 连接到 DMDB

SQL> select * from dual@test_link
select * from dual@test_link
                   *
第 1 行出现错误:
ORA-02085: 数据库链接 TEST_LINK 连接到 DMDB

而再次将XJ库的global_names设为FALSE,则数据库链接又可用了。
SQL> alter system set global_names=false;

系统已更改。

SQL> select * from dual@test_link;

D
-
X

SQL> select * from dual@test_link2;

D
-
X

再将DMDB库的global_names设为FALSE,数据库链接仍然可用:

在DMDB库上:

SQL> alter system set global_names=false;

系统已更改。

在XJ库上:

SQL> select * from dual@test_link;

D
-
X

可以看到,链接仍然可以用。
如果在DMDB库上创建链接到XJ库上,可以观察到同样的结果。
可以得出一个结论:global_names参数设置为FALSE,影响的是创建数据库链接的那个库对数据库链接的使用。也就是说,如果一个库(实例)的global_names参数设值为TRUE,则该库连接其他库的数据库链接,其名称必须要与被连接的库的global_name相同:

在XJ库上:

SQL> alter system set global_names=true;

系统已更改。

SQL> create database link dmdb connect to test identified by test using ‘dmdb’;

数据库链接已创建。

SQL> select * from dual@dmdb;

D
-
X
SQL> select * from dual@test_link;
select * from dual@test_link
*
第 1 行出现错误:
ORA-02085: 数据库链接 TEST_LINK 连接到 DMDB

SQL> select * from dual@test_link2;
select * from dual@test_link2
                   *
第 1 行出现错误:
ORA-02085: 数据库链接 TEST_LINK2 连接到 DMDB

如果在GLOBAL_NAMES设置为TRUE的情况下,如果要建多个数据库链接到同一个库,怎么办呢?因为数据库链接的名称必须与目标库的GLOBAL_NAME相同。可以按如下的方法:

SQL> create database linkdmdb@link1connect to test identified by test using ‘dmdb’;

数据库链接已创建。

SQL> create database linkdmdb@link2connect to test identified by test using ‘dmdb’;

数据库链接已创建。

SQL> select * fromdual@dmdb;

D
-
X

SQL> select * fromdual@dmdb@link1;

D
-
X

SQL> select * fromdual@dmdb@link2;

D
-
X

也就是在GLOBAL_NAME后面加上@再加上一个标识。这样就能够创建多个数据库链接到同一目标库上了。

另外在创建数据库链接时,不能给其他SCHEMA创建链接,这是因为数据库链接(database link)其名称可以含有’.’即点号。比如A用户想给B用户创建一个DBLINK名叫LINKB,CREATE DATABASE LINK B.LINKB ……, 这个语句将会实际创建一个A用户下的名为B.LINKB的数据库链接。

谈谈SET TRANSACTION READ ONLY

Posted by 老熊 on 7月 20th, 2008

SET TRANSACTION READ ONLY类似于SERIALIZABLE事务隔离级别,在发布SET TRANSACTION READ ONLY起的所有SELECT语句,其结果均为同一个时间点一致,直至显式地发布了COMMIT或ROLLBACK命令或隐式提交(执行DDL)。这个时间点为SET TRANSACTION READ ONLY这个语句执行后的时间点。这个语句与SERIALIZABLE不同之处在于,在READ ONLY这个范围内,不能进行DML。以下用测试说明:

用TEST1用户开启两个会话

在会话一中:

SQL> create table t1 (a int );

Table created.

SQL> insert into t1 values (10);

1 row created.

SQL> commit;

Commit complete.

在会话二中:

SQL> select * from t1;

         A
----------
        10

SQL> set transaction read only;

Transaction set.

SQL> select * from t1;

         A
----------
        10
然后在会话一中插入一行数据,并提交:

SQL> insert into t1 values (20);

1 row created.

SQL> commit;

Commit complete.

在会话二中查看表t2的数据:

SQL> /

         A
----------
        10

SQL> /

         A
----------
        10

SQL> commit;

Commit complete.

SQL> select * from t1;

         A
----------
        10
        20

可以看到,虽然会话一已经插入了一条数据并提交了,但是查询时,仍然只能看到一条数据。在COMMIT之后,SET TRANSACTION READ ONLY作用结束,再查询T1,可以看到新插入的数据了。

我们再看一下,这个“时间点”是从第一个SELECT语句的时候还是SET TRANSACTION READ ONLY刚执行完的时候:

在会话二中:

SQL> set transaction read only;

Transaction set.

然后在会话一中:

SQL> insert into t1 values (30);

1 row created.

SQL> commit;

Commit complete.

在会话二中:

SQL> select * from t1;

         A
----------
        10
        20

可以看到,新插入的数据30是在会话二的SET TRANSACTION READ ONLY之后和SELECT之前插入的,但SELECT语句看不到这个数据,因此这个时间点是在执行完SET TRANSACTION READ ONLY之后,而不是第一个SELECT语句执行那一刻。

我们继续下面的测试:

在会话二中:

SQL> drop table t2;

Table dropped.

SQL> select * from t1;

         A
----------
        10
        20
        30

可以看到DROP语句之后,由于隐式提交,SET TRANSACTION READ ONLY作用范围结束,又可以查到新插入的数据。

SQL> set transaction read only;

Transaction set.

SQL> insert into t1 values (40);
insert into t1 values (40)
            *
ERROR at line 1:
ORA-01456: may not perform. insert/delete/update operation inside a READ ONLY
transaction
可以看到,在SET TRANSACTION READ ONLY之后,不能执行DML

注意:SYS用户并不受SET TRANSACTION READ ONLY的影响:

SQL> show user
USER is "SYS"
SQL> set transaction read only;

Transaction set.

SQL> delete from t1 where rownum=1;

1 row deleted.

SQL> commit;

Commit complete.

以上测试即证明了这一点。

EXP导出数据时,如果CONSISTEN参数设为TRUE,则EXP导出时,会先发布SET TRANSACTION READ ONLY,保证所有导出数据在同一时间点上的一致性。当然,如果事务频繁,导出的数据量又大,很可能会遭遇ORA-01555错误。由于SET TRANSACTION READ ONLY对SYS用户无效,用SYS用户导出时CONSISTENT设为TRUE,应该没有效果。有兴趣的朋友可以进行测试。

Primary Key与Unique Key

Posted by 老熊 on 7月 20th, 2008

Primary key 与Unique Key都是唯一性约束。但二者有很大的区别:

1、Primary key的1个或多个列必须为NOT NULL,如果列为NULL,在增加PRIMARY KEY时,列自动更改为NOT NULL。而UNIQUE KEY 对列没有此要求。

2、一个表只能有一个PRIMARY KEY,但可以有多个UNIQUE KEY。

下面以测试说明:

SQL> create table t (a int,b int,c int,d int);

Table created.

SQL> desc t
 Name                                      Null?    Type
 ----------------------------------------- -------- -----------

 A                                                  NUMBER(38)
 B                                                  NUMBER(38)
 C                                                  NUMBER(38)
 D                                                  NUMBER(38)

SQL> alter table t add constraint pk_t primary key (a,b);

Table altered.

SQL> desc t
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------

 A                                         NOT NULL NUMBER(38)
 B                                         NOT NULL NUMBER(38)
 C                                                  NUMBER(38)
 D                                                  NUMBER(38)

可以看到A、B两个列都自动改为了NOT NULL

SQL> alter table t modify (a int null);
alter table t modify (a int null)
                      *
ERROR at line 1:
ORA-01451: column to be modified to NULL cannot be modified to NULL
可以看到,列A不允许改为NULL

SQL> alter table t drop constraint pk_t;

Table altered.

SQL> alter table t add constraint uk_t_1 unique (a,b);

Table altered.

SQL> desc t
 Name                                      Null?    Type
 ----------------------------------------- -------- -----------

 A                                                  NUMBER(38)
 B                                                  NUMBER(38)
 C                                                  NUMBER(38)
 D                                                  NUMBER(38)

我们看到列A又变回了NULL。

注意到,在删除主键时,列的NULLABLE会回到原来的状态。如果在创建主键后,对原来为NULL的主键列,显式设为NOT NULL,在删除主键后仍然是NOT NULL。比如在创建主键后,执行下面的操作,可以看到:

SQL> alter table t modify (b int not null);

Table altered.

SQL> alter table t drop constraint pk_t;

Table altered.

SQL> desc t
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------

 A                                                  NUMBER(38)
 B                                         NOT NULL NUMBER(38)
 C                                                  NUMBER(38)
 D                                                  NUMBER(38)

再做如下的实验:

SQL> drop table t;

Table dropped.

SQL> create table t (a int,b int,c int,d int);

Table created.

SQL> alter table t add constraint uk_t_1 unique (a,b);

Table altered.

SQL> alter table t add constraint uk_t_2 unique (c,d);

Table altered.

可以看到可以增加两个UNIQUE KEY。看看能不能增加两个主键:

SQL> alter table t add constraint pk_t primary key (c);

Table altered.

SQL> alter table t add constraint pk1_t primary key (d);
alter table t add constraint pk1_t primary key (d)
                                  *
ERROR at line 1:
ORA-02260: table can have only one primary key
由此可以看到一个表只能有一个主键。

SQL> alter table t drop constraint pk_t;

Table altered.

SQL> insert into t (a ,b ) values (null,null);

1 row created.

SQL> /

1 row created.

SQL> insert into t (a ,b ) values (null,1);

1 row created.

SQL> /
insert into t (a ,b ) values (null,1)
*
ERROR at line 1:
ORA-00001: unique constraint (SYS.UK_T_1) violated

SQL> insert into t (a ,b ) values (1,null);

1 row created.

SQL> /
insert into t (a ,b ) values (1,null)
*
ERROR at line 1:
ORA-00001: unique constraint (SYS.UK_T_1) violated

主键和唯一键约束是通过参考索引实施的,如果插入的值均为NULL,则根据索引的原理,全NULL值不被记录在索引上,所以插入全NULL值时,可以有重复的,而其他的则不能插入重复值。

学习笔记之shutdown transactional

Posted by 老熊 on 7月 20th, 2008

关于ORACLE 的transactional方式下的shutdown ,做了一下实验,记录之:

正常启动ORACLE之后,开三个连接到ORACLE。

在session2执行
SQL> delete from t1 where rownum=1;

1 row deleted.

在session 3执行
SQL> delete from t2 where rownum=1;

1 row deleted.

在session1执行
SQL> shutdown transactional;

这个session会挂起。

我们在session2执行如下的语句:
SQL> rollback;

Rollback complete.

SQL> delete from t1 where rownum=1;
delete from t1 where rownum=1
            *
ERROR at line 1:
ORA-01089: immediate shutdown in progress - no operations are permitted
SQL> select 1 from dual;

         1
----------
         1

可以看到,事务回滚后,不能开启新的事务了。但是可以进行查询操作

现在我们在session3中回滚事务:
SQL> rollback;

回退已完成。

这个时候在session 1中就会出现:
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL>

结论:以transactional方式关闭数据库,当客户端的事务完成后(commit 或 rollback),客户端就不能再次开始一个新的事务,但是可以进行查询。当所有客户端的事务完成后,服务器就会强制断开所有连接,然后关闭数据库。

另外,在以normal方式关闭数据库时,已有的连接不受任何影响,可以新开始一个事务。只是不允许连接新的用户。只有所有的用户都disconnect后,实例才能关闭。对于一个实际的业务系统来说,几乎是一个“不可能完成的任务”。

如何在SQLPLUS中获取SHELL执行后的返回结果

Posted by 老熊 on 7月 20th, 2008

有网友在ITPUB上问到“sqlplus下如何获取shell的return code”

可以用以下的办法:

在SHELL中把结果重定向到一个文件。
举个例子:
所有的测试文件都放在$HOME下
func.sh是你要执行操作的SHELL

#!/bin/sh
exit 2

test.sh的功能就是调用func.sh
#!/bin/sh
$HOME/func.sh
echo "define VAR_TEST=$?" > $HOME/test.sql

在SQLPLUS中
SQL > host $HOME/test.sh
SQL > @$HOME/test.sql

现在就定义了一个SQLPLUS的变量VAR_TEST。
SQL > select ‘&VAR_TEST’ x from dual;

old    1: select ‘&VAR_TEST’ x from dual
new  1:select ‘2′ x from dual

x
--
2

ORACLE的动态注册行为

Posted by 老熊 on 7月 20th, 2008

大家都知道,ORACLE实例在启动时,或使用命令ALTER SYSTEM REGISTER 或每隔一分钟,实例的PMON会向监听进行注册,告知监听,实例的服务名,实例名等信息。

不同的平台有不同的行为,本文所描述的是在LINUX下的行为。ORACLE版本为10.2.0.1。

讲到动态注册,跟监听密切相关,下面先看看监听的行为:

监听在启动时,会从$ORACLE_HOME/network/admin/listener.ora读取监听配置,如果该文件不存在,则监听会在主机名对应的IP和1521端口上进行监听。如果主机名在/etc/hosts里没有配置(或不能通过DNS解析---这是我的猜想,没有验证),则在等待较长一段时间后,将在所有的地址上(0.0.0.0:1521)进行监听,但此时实例并不会进行动态注册,客户端可通过主机的任意IP地址连接,但均会报ORA-12514错误。除非设置LOCAL_LISTENER参数,将本地LISTENER地址指向本机的任意一IP。

如果存在listener.ora文件,则监听会根据该文件配置内容进行启动。如果主机名在/etc/hosts没有条目,监听 启动比较慢(可能是监听起来后,在根据主机名作什么操作),因此必须要保证主机名要在/etc/hosts中有记录。

同一个网络接口(网卡)上,如果绑定了两个或以上的IP地址,则监听这样的网络接口时,最多只能使用一个主机名,比如:

[oracle@xty ~]$ cat /etc/hosts
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1       localhost.localdomain   localhost
192.168.0.114   xty
192.168.0.115   xty_vip
192.168.0.116   xty_vip2

这里xty和xty_vip对应的IP绑定在同一网卡上

cat listener.ora

# Generated by Oracle configuration tools.

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = /u01/app/oracle/oracle/product/10.2.0/db_1)
      (PROGRAM = extproc)
    )
  )

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = xty_vip )(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = xty )(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = xty_vip2 )(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
    )
  )

启动监听时,报下面的错误:

TNSLSNR for Linux: Version 10.2.0.1.0 - Production
System parameter file is /u01/app/oracle/oracle/product/10.2.0/db_1/network/admi
n/listener.ora
Log messages written to /u01/app/oracle/oracle/product/10.2.0/db_1/network/log/l
istener.log
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521
)))
Error listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521)))
TNS-12542: TNS:address already in use
 TNS-12560: TNS:protocol adapter error
  TNS-00512: Address already in use
   Linux Error: 98: Address already in use

Listener failed to start. See the error message(s) above…

将listener.ora中的(ADDRESS = (PROTOCOL = TCP)(HOST = xty )(PORT = 1521))行,改为(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.114 )(PORT = 1521)),则监听能够正常启动

下面再来看一下PMON向监听注册实例的行为:

在缺省情况下(也就是没有LOCAL_LISTENER参数配置的情况下),PMON会根据主机名(hostname),查找其IP地址,通常是在/etc/hosts中找对应的条目,如果没有找到hostname的IP地址,则PMON不会注册,同时,必须是本机的IP地址,PMON才能注册。比如在/etc/hosts中将hostname对应的IP地址改为其他非本机的IP地址,PMON也不会进行注册。PMON根据hostname找到IP后,同时判断这个是本机IP,则会通过这个IP连接至监听进行注册。如果listener没有监听这个IP,则PMON也不会注册,因为通过这个IP连接不上监听。

举一个简单的例子,现有两台IBM小机,作双机热备,双机采用HACMP。在监听设置中,只监听了HA的服务IP地址,而hostname对应的IP地址为服务IP绑定的网卡上的另一个地址。在这种情况下,PMON不能进行动态注册,在客户端连接这个ORACLE服务器时,将会报ORA-12514错误。

解决上面提到的这个问题的办法,除了静态注册(本文主要讨论动态注册),还有两种办法,第一种我个人认为最好的一种,是在LISTENER上监听两个IP地址,类似于下面这样:

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = xty_vip )(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.114 )(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
    )
  )

另一个办法就是设置LOCAL_LISTENER参数,假如LISTENER只监听了xty_vip(192.168.0.115)这个地址,则通过下面的命令设置LOCAL_LISTENER:

    ALTER SYSTEM SET LOCAL_LISTENER=’ (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.115 )(PORT = 1521))’

这里建议使用IP地址,特别是对RAC,后文细述。

LOCAL_LISTENER使PMON改变用hostname连接LISTENER进行注册的默认行为。改而用LOCAL_LISTENER参数指定的地址连接LISTENER进行注册。当然LOCAL_LISTENER指定的IP地址必须是本机的IP地址。如果是非本机IP,则会忽略此参数,但是会从前一个已注册的监听中取消注册。

与LOCAL_LISTENER对应的参数有REMOTE_LISTENER参数。REMOTE_LISTENER使PMON在远程(即非本机)监听上进行注册,这个参数在RAC中经常使用(用于负载均衡)。

下面来作一个测试

主机1,LINUX AS4
主机2,Windows 2003,IP地址:192.168.0.100

,在主机2上启动监听:
D:\oracle\product\10.2.0\db_1\BIN>lsnrctl start

LSNRCTL for 32-bit Windows: Version 10.2.0.1.0 - Production on 02-2月 -2008 09:5
6:44

Copyright (c) 1991, 2005, Oracle.  All rights reserved.

启动tnslsnr: 请稍候…

TNSLSNR for 32-bit Windows: Version 10.2.0.1.0 - Production
写入d:\oracle\product\10.2.0\db_1\network\log\listener.log的日志信息
监听: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dreamf)(PORT=1521)))

正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
LISTENER 的 STATUS
------------------------
别名                      LISTENER
版本                      TNSLSNR for 32-bit Windows: Version 10.2.0.1.0 - Produ
ction
启动日期                  02-2月 -2008 09:56:47
正常运行时间              0 天 0 小时 0 分 3 秒
跟踪级别                  off
安全性                    ON: Local OS Authentication
SNMP                      OFF
监听程序日志文件          d:\oracle\product\10.2.0\db_1\network\log\listener

监听端点概要…
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dreamf)(PORT=1521)))
监听程序不支持服务
命令执行成功

在主机1上启动监听:
[oracle@xty ~]$ lsnrctl start

LSNRCTL for Linux: Version 10.2.0.1.0 - Production on 01-FEB-2008 17:28:57

Copyright (c) 1991, 2005, Oracle.  All rights reserved.

Starting /u01/app/oracle/oracle/product/10.2.0/db_1/bin/tnslsnr: please wait…

TNSLSNR for Linux: Version 10.2.0.1.0 - Production
System parameter file is /u01/app/oracle/oracle/product/10.2.0/db_1/network/admi
n/listener.ora
Log messages written to /u01/app/oracle/oracle/product/10.2.0/db_1/network/log/l
istener.log
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521
)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.114)(PORT=1521
)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC0)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=xty_vip)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 10.2.0.1.0 - Production
Start Date                01-FEB-2008 17:28:57
Uptime                    0 days 0 hr. 0 min. 0 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   /u01/app/oracle/oracle/product/10.2.0/db_1/network/adm
in/listener.ora
Listener Log File         /u01/app/oracle/oracle/product/10.2.0/db_1/network/log
/listener.log
Listening Endpoints Summary…
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.114)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC0)))
Services Summary…
Service "PLSExtProc" has 1 instance(s).
  Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service…
The command completed successfully
[oracle@xty ~]$

然后在主机1上启动数据库。输入命令:

alter system set remote_listener=’(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.100)(PORT=1521))’;

在主机2上查看LISTENER的状态

正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
LISTENER 的 STATUS
------------------------
别名                      LISTENER
版本                      TNSLSNR for 32-bit Windows: Version 10.2.0.1.0 - Produ
ction
启动日期                  02-2月 -2008 09:56:47
正常运行时间              0 天 0 小时 16 分 54 秒
跟踪级别                  off
安全性                    ON: Local OS Authentication
SNMP                      OFF
监听程序日志文件          d:\oracle\product\10.2.0\db_1\network\log\listener.log

监听端点概要…
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=dreamf)(PORT=1521)))
服务摘要..
服务 "XTY" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
服务 "XTY1XDB" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
服务 "XTY_XPT" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
命令执行成功

在主机2上再执行lsnrctl service命令:

D:\oracle\product\10.2.0\db_1\BIN>lsnrctl service

LSNRCTL for 32-bit Windows: Version 10.2.0.1.0 - Production on 02-2月 -2008 10:
5:21

Copyright (c) 1991, 2005, Oracle.  All rights reserved.

正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
服务摘要..
服务 "XTY" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "DEDICATED" 已建立:0 已拒绝:0 状态:ready
         REMOTE SERVER
         (ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521))
服务 "XTY1XDB" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "D000" 已建立:0 已被拒绝:0 当前: 0 最大: 1022 状态: ready
         DISPATCHER <machine: xty, pid: 2996>
         (ADDRESS=(PROTOCOL=tcp)(HOST=xty)(PORT=32801))
服务 "XTY_XPT" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "DEDICATED" 已建立:0 已拒绝:0 状态:ready
         REMOTE SERVER
         (ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521))
命令执行成功

主机1上的实例已经成功注册到主机2上的监听

在主机2上的TNSNAMES.ORA中有:

XTY_R =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.100)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = xty)
    )
  )

在主机2上连接XTY_R(这个实例实际运行在主机1上)

D:\oracle\admin\XJ\bdump>sqlplus test/test@xty_r

SQL*Plus: Release 9.2.0.1.0 - Production on 星期六 2月 2 10:19:41 2008

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

ERROR:
ORA-12535: TNS: 操作超时

请输入用户名:

报了ORA-12536错误。

从上面的lsnrctl service命令可以查看到REMOTE SERVER的地址为:
(ADDRESS=(PROTOCOL=TCP)(HOST=xty)(PORT=1521))
因此客户端连接时,LISTENER判断这是个远程SERVER,会将这个地址返回给客户,客户端再去连接这个地址。但这里HOST=xty,客户端不能解析这个地址,所以就报超时错误。

但如果在主机1上的数据库中执行下面的命令:
alter system set local_listener=’(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))’;

我们再看看主机2上的LISTENER SERVICE:

正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
服务摘要..
服务 "XTY" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "DEDICATED" 已建立:0 已拒绝:0 状态:ready
         REMOTE SERVER
         (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
服务 "XTY1XDB" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "D000" 已建立:0 已被拒绝:0 当前: 0 最大: 1022 状态: ready
         DISPATCHER <machine: xty, pid: 2996>
         (ADDRESS=(PROTOCOL=tcp)(HOST=xty)(PORT=32801))
服务 "XTY_XPT" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "DEDICATED" 已建立:0 已拒绝:0 状态:ready
         REMOTE SERVER
         (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
命令执行成功

注意看到上面REMOTE SERVER已经变成了 (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
这个时候再次连接,由成功连接到ORACLE服务器上:

D:\oracle\admin\XJ\bdump>sqlplus test/test@xty_r

SQL*Plus: Release 9.2.0.1.0 - Production on 星期六 2月 2 10:39:25 2008

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

连接到:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL>

在RAC中,服务器开启了负载均衡,则客户端有时连接时会出现ORA-12514错误,这里需要设置LOCAL_LISTENER参数,以解决该问题。

注意:在通过REMOTE_LISTENER参数向远程监听注册时,本地的LISTENER也需要处于启动状态,否则监听中服务的状态为BLOCKED状态:

正在连接到 (ADDRESS=(PROTOCOL=tcp)(HOST=)(PORT=1521))
服务摘要..
服务 "XTY" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "DEDICATED" 已建立:1 已拒绝:0 状态:blocked
         REMOTE SERVER
         (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
服务 "XTY1XDB" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "D000" 已建立:0 已被拒绝:0 当前: 0 最大: 1022 状态: ready
         DISPATCHER <machine: xty, pid: 2996>
         (ADDRESS=(PROTOCOL=tcp)(HOST=xty)(PORT=32801))
服务 "XTY_XPT" 包含 1 个例程。
  例程 "XTY1", 状态 READY, 包含此服务的 1 个处理程序…
    处理程序:
      "DEDICATED" 已建立:1 已拒绝:0 状态:blocked
         REMOTE SERVER
         (ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.115)(PORT=1521))
命令执行成功

而这个时候客户端连接报ORA-12516错误

另外,数据库实例版本必须与LISTENER版本兼容,否则不能进行动态注册。

本文主要是通过实验和分析网络包,然后进行总结的结果,没有参考相关的理论文档。有所错误在所难免,欢迎讨论。

LOB列类型的LOGGING和NOLOGGING存储选择

Posted by 老熊 on 7月 20th, 2008

众所周知,如果一个库没有设置为force logging,而这个库在归档模式下,对表的插入操作如果采用APPEND模式,并且表设置为nologging则不会为插入的数据产生日志。那么对LOB列的存储也设置为NOLOGGING,会产生什么样的结果?

测试环境:Oracle 9.2.0.1 for Win,非归档模式

create table test1.t1(id int not null, out_row clob)
lob(out_row) store as (disable storage in row nocache nologging);

关闭数据库,备份数据文件users01.dbf

启动数据库,将表中插入数据:

insert into test1.t1 select rownum,rpad(’x',5000,’x') from dba_objects where rownum<=100;

select * from test1.t1;

能够正常返回100行数据。

关闭数据库,用备份的文件还原文件users01.dbf,启动数据库时报错:

数据库装载完毕。
ORA-01113: ?? 5 ??????
ORA-01110: ???? 5: ‘D:\ORACLE\ORADATA\XJ\USERS01.DBF’

SQL> recover datafile 5;
完成介质恢复。

SQL> alter session set nls_language=american;

Session altered.
SQL> alter database open;

Database altered.

SQL> select count(*) from test1.t1;

  COUNT(*)
----------
       100

SQL> select * from test1.t1;
ERROR:
ORA-01578: ORACLE data block corrupted (file # 5, block # 61)
ORA-26040: Data block was loaded using the NOLOGGING option
ORA-01110: data file 5: ‘D:\ORACLE\ORADATA\XJ\USERS01.DBF’

由此可以看出,在此前的插入操作中,没有对LOB数据产生日志。

我们将test1.t1删除,再重新创建,只是将LOB设置为LOGGING。

SQL> drop table test1.t1;

表已丢弃。

SQL> create table test1.t1 (id number not  null,out_row clob)
  2  lob (out_row) store as (disable storage in row nocache logging);

重复上步实验过程,发现LOGGING模式下的LOB能够正常恢复。

将数据库设置为归档模式,重复以上测试过程,发现NOLOGGING模式下的LOB仍然不能恢复。

将数据库设置为FORCE LOGGING模式,重复以上测试过程,发现NOLOGGING模式下的LOB能够正常恢复。

经过进一步测试,对LOB字段进行UPDATE也会产生上述实验结果。

在这个测试中使用了一个比较“笨”的办法。观察LOB列是否产生日志,可以观察redo size和分析日志文件进行。在此不在细述。

经过测试,发现IN ROW的LOB列与表中的其他列数据是一致的LOGGING行为。

注意:LOB列如果设置为CACHE,则只能是LOGGING模式。

由此引出一个问题,由于对LOB列设置为NOLOGGING,虽然能够提高数据插入速度,为数据恢复设置了一道难关。需要此种情况下的备份恢复策略,或者将LOB列设置为LOGGING模式。

Oracle10g下手工重建CRS和RAC数据库

Posted by 老熊 on 7月 20th, 2008

某个刚安装好的RAC库,由于需要更换存储,所以需要重建。由于主机系统并没有重新安装,因此只需要重建CRS和库就行了。

环境:AIX 5306+HACMP 5.2+ORACLE 10.2.0.1+祼设备,文中对节点名、网络配置等信息处了更改处理。

以下是详细操作步骤:

1、在两个节点上修改主机配置:由于网络变更的原因,需要更换VIP,因此修改/etc/hosts文件,将VIP地址对应的地址更改为新的IP地址

2、在两个节点上修改/etc/oracle/ocr.loc文件,将文件中的ocrconfig_loc=后的地址改为新的存储ocr的祼设备名(如果用的是集群文件系统,则为文件名)

3、在两个节点上删除文件/etc/oracle/scls_scr/<节点名>/oracle/cssfatal

4、在两个节点上,进入$ORA_CRS_HOME/install目录,修改paramfile.crs文件,修改变动的配置数据。这里主要包括CRS_OCR_LOCATIONS、CRS_VOTING_DISKS、CRS_NODEVIPS

5、对存储OCR CONFIG的祼设备,用dd命令进行清除。(如果是集群文件系统,只需要删除OCR CONFIG的文件即可)。这里祼设备名为rocr,dd if=/dev/zero f=/dev/rocr bs=4096 count=10000 (如果是OCR本来是存在,只是需要重建,则必须要执行这一步。就算是完全新建在祼设备上,在后面的步骤中有时也会遇到莫名其妙的问题,则也需要对祼设备用dd进行清除,dd清除的大小不能过小,bs=4096的情况下,count为10之类的数值就显得过小,后面也会出现问题)

6、在两个节点上修改文件$ORA_CRS_HOME/install/rootconfig,修改在文件前面的变量。这里也主要是CRS_OCR_LOCATIONS、CRS_VOTING_DISKS、CRS_NODEVIPS

7、如果是通过远程telnet、ssh在主机上操作,则要设置DISPLAY变量。export DISPLAY=x.x.x.x:0.0。这里x.x.x.x为操作的终端的IP地址。在操作终端上运行如xmanager这样的软件。

7、在节点一上以root用户运行$ORA_CRS_HOME/install/rootconfig,注意不要运行rootinstall

8、待节点一完全运行完后,在节点二上运行$ORA_CRS_HOME/install/rootconfig。正常情况下会弹出vip设置窗口。如果VIP设置窗口没有弹出来,则看一下是否只是vipca启动出现问题。

9、在两个节点上运行crs_stat -t,如果出现CRS没有资源或有VIP相关的资源启动(在VIP已经设置的情况下),说明CRS已经建立成功。

10、如果前面没有配置VIP,则以root用户运行vipca,配置VIP。注意在弹出的窗口中,提示选择网络接口时,选择public接口。(如果显示接口异常,在shell用oifcfg命令检查一下网络接口,如有必要,用该命令对网络接口进行重新配置)

11、至此crs已经配置完毕,用crs_stat检查crs是否正常运行。如果没有正常运行,检查crs日志。此时应该有VIP、ONS、GSD等资源运行。在两个节点上运行ifconfig -a检查VIP是否已经绑定到PUBLIC网卡上(注意要确保是在PUBLIC网卡上,有的时候粗略一下VIP已经起了,但实际上绑在了PRIVATE网卡上)

12、清除原来的监听设置,确认监听是处于关闭状态,运行netca,配置监听,配置完成后将会自动把监听加入到crs中。

12、由于存在原来的建库脚本,打开原来的脚本,修改对应的数据文件名为新的文件名(祼设备名)

13、在节点一上运行建库脚本(shell脚本)

14、一番耐心等候之后,在节点一上的数据库创建完成

15、在节点二上运行建库脚本(shell脚本),这个过程很快

16、在两个节点上修改tnsnames.ora,内容如下(根据实际情况进行修改):

LISTENERS_DMDB =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = dm1-vip)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = dm2-vip)(PORT = 1521))
)

DMDB =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dm1-vip)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = dm2-vip)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = dmdb)
)
)

RAC2 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dm2-vip)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = dmdb)
(INSTANCE_NAME = rac2)
)
)

RAC1 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dm1-vip)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = dmdb)
(INSTANCE_NAME = rac1)
)
)

EXTPROC_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
)
(CONNECT_DATA =
(SID = PLSExtProc)
(PRESENTATION = RO)
)
)

17、修改两个节点的初始化参数REMOTE_LISTENERS为 ‘LISTENERS_DMDB’,节点一的LOCAL_LISTENER=’(ADDRESS = (PROTOCOL = TCP)(HOST = IP1 )(PORT = 1521))’,节点二的
LOCAL_LISTENER=’(ADDRESS = (PROTOCOL = TCP)(HOST = IP2)(PORT = 1521))’,注意这里的IP1和IP2分别是节点一和节点二的VIP地址(注意一定是IP地址,而不能是主机名)。设置LOCAL_LISTENER的目的是避免在使用负载均衡时出现ORA-12545错误。

18、在其中一个结点上创建spfile,这里spfile为祼设务rspfile:create spfile=’/dev/rspfile’ from pfile=’xxxx’

19、关闭两个节点的实例。将数据库和实例增加到crs中,以便能够能用crs命令进行监控和用srvctl命令启停数据库实例:

srvctl add database -d dbname -o $ORACLE_HOME -y manual
srvctl add instance -d dbname -n 节点名1 -i 实例名1
srvctl add instance -d dbname -n 节点名2 -i 实例名2

这里实例名1和实例名2应分别与两个节点的ORACLE_SID一致

注意:10.2.0.1版本,实例依赖于VIP,因此如果某结点如网卡DOWN掉、VIP BUG等,将导致实例也DOWN掉。为避免出现这样的情况,可省略此步骤,不要将实例加入到CRS资源中。

至此所有工作已经全部完成

exp导出表名为小写的表

Posted by 老熊 on 7月 20th, 2008

由于ORACLE默认的表名都是不区分大小写,在创建表时,在数据字典中存储的表名为大写。在有些情况下,如果创建的表在表名上加上双引号("),则创建的表其表名在数据字典中不作转换。比如

create table test1."Table1" as select * from dba_objects where rownum<=10;

表已创建。

select table_name from dba_tables where owner=’TEST1′;

TABLE_NAME
------------------------------------------------------------
T1
T2
Table1
tt

 

可以看到刚创建的Table1表在数据字典中为"Table1"而不是TABLE1

在导出这样的表时,按用户导出是没有问题的:

exp test1/test1 wner=test1

. 即将导出 TEST1 的表通过常规路径 …
. . 正在导出表 T1 0 行被导出
. . 正在导出表 T2 0 行被导出
. . 正在导出表 Table1 10 行被导出
. . 正在导出表 tt 10 行被导出

而要单独导出表的话,则需求作特殊处理

exp test1/test1 tables=Table1

即将导出指定的表通过常规路径 …
EXP-00011: TEST1.TABLE1 不存在
导出成功终止,但出现警告。

将table1用双引号或单引号引起也是一样

exp test1/test1 tables=\"Table1\"

也是一样的结果

用下面的写法可以成功

exp test1/test1 tables=’\"Table1\"’

即将导出指定的表通过常规路径 …
. . 正在导出表 Table1 10 行被导出
在没有警告的情况下成功终止导出。

用参数文件时,由用tables=’"Table1"’,去掉反斜杠

注意tables=’\"Table1\"’这里是外面一个单引号加反斜杠再加一双引号

oracle对JOB失败的处理

Posted by 老熊 on 7月 20th, 2008

在job执行过程中,all_jobs中,this_date和this_sec记录本次开始执行的时间。next_date和next_sec则在开始执行时按interval计算好。执行完成后,无论失败与否,last_date和last_sec为上次执行(也即刚执行过)开始的时间。next_date和next_sec为下次开始执行时间。

如果执行失败,failures字段加1,同时下次执行时间为本次执行时间+2分钟(不知这两分钟从何而来,有空再研究一下),如果再次失败,由下次执行的时间为上次开始执行时间+4,再次失败则+8,以此类推。

执行成功后,failures字段清0.


Copyright © 2007 老熊的三分地-Oracle、UNIX、数据恢复. All rights reserved.