Oracle10g 在AIX 5.3上的安装

Posted by 老熊 on 7月 20th, 2008

Oracle10g 在AIX 5.3上的安装

今天无事,在单位的测试机上,安装了一下Oracle10g

环境:AIX 5.3 ML06 ,数据库版本 : Oracle 10g for AIX 5L 64bit

简单记录了一下安装过程:

   检查硬件配置
   检查内存:
   # lsattr -El sys0 -a realmem
   realmem 2097152 Amount of usable physical memory in Kbytes False
   检查交换空间
   # lsps -a
   Page Space      Physical Volume   Volume Group    Size %Used Active  Auto  Type
   hd6             hdisk0            rootvg         512MB     1   yes   yes    lv
   检查临时文件目录(至少应有400M空闲空间)
   df -k /tmp
   Filesystem    1024-blocks      Free %Used    Iused %Iused Mounted on
   /dev/hd3            65536     63984    3%       16     1% /tmp  
   检查操作系统位数
   # getconf HARDWARE_BITMODE
   64
   检查操作系统版本号
   # oslevel -r
   5300-06
   检查安装的软件包:
   # lslpp -l bos.adt.base bos.adt.lib bos.adt.libm bos.perf.perfstat bos.perf.libperfstat bos.perf.proctools bos.adt.prof bos.cifs_fs.rte
  Fileset                      Level  State      Description        
  ----------------------------------------------------------------------------
Path: /usr/lib/objrepos
  bos.adt.base              5.3.0.60  COMMITTED  Base Application Development
                                                 Toolkit
  bos.adt.lib               5.3.0.60  COMMITTED  Base Application Development
                                                 Libraries
  bos.adt.libm              5.3.0.60  COMMITTED  Base Application Development
                                                 Math Library
  bos.adt.prof              5.3.0.60  COMMITTED  Base Profiling Support
  bos.cifs_fs.rte           5.3.0.60  COMMITTED  Runtime for SMBFS
  bos.perf.libperfstat      5.3.0.60  COMMITTED  Performance Statistics Library
                                                 Interface
  bos.perf.perfstat         5.3.0.60  COMMITTED  Performance Statistics
                                                 Interface
  bos.perf.proctools        5.3.0.60  COMMITTED  Proc Filesystem Tools

Path: /etc/objrepos
  bos.cifs_fs.rte           5.3.0.60  COMMITTED  Runtime for SMBFS
  bos.perf.libperfstat      5.3.0.60  COMMITTED  Performance Statistics Library
                                                 Interface
  bos.perf.perfstat         5.3.0.60  COMMITTED  Performance Statistics
                                                 Interface

对于缺少的包,用installp -a -d /dev/cd0 包名  进行安装,安装时放入AIX的安装光备                                    

检查安装的补丁包
# /usr/sbin/instfix -i -k "IY58143 IY59386 IY60930 IY66513 IY70159"
    All filesets for IY58143 were found.
    All filesets for IY59386 were found.
    All filesets for IY60930 were found.
    All filesets for IY66513 were found.
    All filesets for IY70159 were found.

# /usr/sbin/instfix -i -k "IY68989"
    All filesets for IY68989 were found.

安装AIX C++ 8.0 运行时

编辑/etc/hosts文件
   
创建用户组oinstall,dba
mkgroup -’A’ oinstall
mkgroup -’A’ dba
创建用户oracle
修改oracle用户密码
确认nobody用户存在 id nobdy
配置shell limits( smit chuser)
  soft FILE size -1
  soft CPU time -1
  soft DATA segment -1
  soft STACK size -1
更改系统参数 smit chgsys
  将 Maximum number of PROCESSES allowed per user改为2048以上
 
创建目录
# mkdir -p /u01/app/oracle
# chown oracle:oinstall /u01/app/oracle
# chmod 775 /u01/app/oracle
# mkdir -p /u02/oradata
# chown oracle:oinstall /u02/oradata
# chmod 755 /u02/oradata

创建文件系统/u01 /u02
   
切换到oracle用户,在.profile中增加如下两行
umask 022
AIXTHREAD_SCOPE=S; export AIXTHREAD_SCOPE
ORACLE_BASE=/u01/app/oracle; export ORACLE_BASE

执行
  . ./.profile
将安装文件ftp到主机
解压文件
gunzip 10gr2_aix5l64_database.cpio.gz
cpio -idmv  10gr2_aix5l64_database.cpio (如果报0511-903 Out of phase这样的错误,cpio命令加上c 这个参数,即idmcv)                                                  
以root用户执行 Disk1/rootpre/rootpre.sh
切换回oracle用户
export DISPLAY
运行Disk1/runInstaller完成安装

完成后注意修改操作系统maxperm% maxclient% minperm% v_pinshm strict_maxclient strict_maxperm参数

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参数设置为TRUE(感谢Robert.Li指出的此前的错误),影响的是创建数据库链接的那个库对数据库链接的使用。也就是说,如果一个库(实例)的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\"’这里是外面一个单引号加反斜杠再加一双引号


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