Tuesday, May 29, 2007

10G B14211-01

今天起开始阅读Oracle® Database Performance Tuning Guide 10g Release 2 (10.2)
这篇主要讲述10G性能调整的方方面面,虽然有关性能的话题总是牵连广泛,比如底层硬件,CPU,内存,网络,存储,firmware版本,RAID,OS,内核版本,内核参数....但是这里主要关注如何在其他因素确定的情况下,调整Oracle的性能。

Wednesday, May 23, 2007

最近在干什么

最近我在看10g RMAN的文档,如何利用rman进行高级复制,重建数据库。
还有就是对照OCM的考试大纲一个一个的练习和做实验。
准备今年内参加OCM的考试。
英语啊英语,我的口语怎么练习呢?
很想背一背,但是找不到好的材料。

Thursday, May 17, 2007

记录一个批处理文件的写法

do.bat
@echo Straing load COC data from ADE tab flat file
@for /f %%A in ('"dir /a:d /b "') do @dir %%A /s /b >> temp.tmp
@rem 这里首先取到当前目录下面的所有子目录中的文件(只有一层),保存在temp.tmp里面
@find "TEX" temp.tmp > temp.names
@rem 过滤temp.tmp的内容,之保留带有TEX结尾的文件。
@for /f "skip=2" %%A in ('"type temp.names "') do @call extract %%A
@rem 用extract脚本收取每个文件当中的内容

@REM *********************
@for /f %%A in ('"dir /a:d /b "') do @rd %%A /q /s
@del temp.tmp
@del temp.names
@del temp.log
@del temp.bad
@rem 收尾工作
@echo wwwwwwwwwwwwwwwwork is doneeeeeeeeeeeeeeeeee

extract.bat
@echo in
@sqlldr userid=COC_COLLECTION/coc@mycim control=extractData.ctl data=%1 skip=200 log=temp.log bad=temp.bad
@sqlldr userid=COC_COLLECTION/coc@mycim control=extractParameter.ctl data=%1 log=temp.log bad=temp.bad
@sqlldr userid=COC_COLLECTION/coc@mycim control=extractOrder.ctl data=%1 log=temp.log bad=temp.bad
@sqlplus COC_COLLECTION/coc@mycim @run.txt
@echo out

extractData.ctl
OPTIONS (ERRORS=10000, SILENT=(ALL), READSIZE=2097152 )
load data
infile *
replace INTO TABLE data
(
CLASSNUM position(1:7) "case when to_char(:CLASSNUM) like '%****%' then null else to_number(:CLASSNUM) end",
AMOUNT position(*:16) "case when to_char(:AMOUNT) like '%****%' then null else to_number(:AMOUNT) end",
MAX position(*:24) "case when to_char(:MAX) like '%****%' then null else to_number(:MAX) end",
MIN position(*:33) "case when to_char(:MIN) like '%****%' then null else to_number(:MIN) end",
MEAN position(*:42) "case when to_char(:MEAN) like '%****%' then null else to_number(:MEAN) end",
DELTA position(*:51) "case when to_char(:DELTA) like '%****%' then null else to_number(:DELTA) end",
MAX_DEV position(*:60) "case when to_char(:MAX_DEV) like '%****%' then null else to_number(:MAX_DEV) end",
STD_DEV position(*:69) "case when to_char(:STD_DEV) like '%****%' then null else to_number(:STD_DEV) end",
CV position(*:78) "case when to_char(:CV) like '%****%' then null else to_number(:CV) end"
)

extractParameter.ctl
OPTIONS (ERRORS=10000, SILENT=(ALL), READSIZE=2097152 )
LOAD DATA
INFILE *
REPLACE
CONTINUEIF THIS (1) = '"'
INTO TABLE para
(
a terminated by '"' "case when to_char(:a) is null then 'notmeasured' else to_char(:a) end",
b terminated by 'Total'
)

extractOrder.ctl
Load data
infile *
replace
INTO TABLE po
WHEN (2:12) = 'Plant Order'
(
PO position(13:100)
)


Monday, May 14, 2007

X86_64笔记本上安装Red hat AS4u4 + Oracle 10g R2 + ASM

这篇文章主要向你介绍,如何在只有一块物理硬盘的linux环境下,安装带ASM的Oracle 10g。

首先用grub引导机器,进入grub的命令行。
kernel (hd0,10)/as4/vmlinuz
Initrd (hd0,10)/as4/initrd.img
boot

然后从硬盘选择iso镜像,安装Red hat AS4u4。

Oracle 10g的安装选择silent模式。
1. 省略前期的内核配置,用户权限配置,用户环境变量配置。
2. 录制安装脚本

$./runInstaller –record –destinationFile /tmp/install_scripts.rsp
进入安装界面后,按照需求选择,最后一步的时候cancel掉。(注意选择software only)
3. 使用录制脚本安装
$./runInstaller –silent –force –ignoreSysprereqs –responseFile /tmp/install_scripts.rsp
4. Post installation actions
步骤3结束以后,需要运行两个脚本。
$ORACLE_BASE/oraInvntory/orainstRoot.sh
$ORACLE_HOME/root.sh
至此Oracle 10g R2安装结束。
5. 卸载
$./runInstaller –silent –deinstall –removeallfiles –removeAllPatches –responseFile /tmp/install_scripts.rsp

ASM
Automatic Storage Management是专门为Oracle数据库提供的一个逻辑卷管理器,提供数据条带化,磁盘IO负载均衡以及数据冗余。
通常情况下,ASM建立在若干硬盘之上,这样可以保证数据冗余以及IO负载均衡。
由于是在笔记本上搭建这样的环境,我只有一个硬盘,那么就需要通过loopback devices来模拟多个硬盘。
下面介绍整个ASM的安装过程
1. 制作“本地磁盘”
创建一个目录
mkdir /asmdisks
创建若干用来模拟本地硬盘的大文件。由于在linux下,touch命令产生的稀疏文件,所以这里使用dd命令。
dd if=/dev/zero of=/asmdisks/disk1 bs=1024k count=1000
dd if=/dev/zero of=/asmdisks/disk2 bs=1024k count=1000
dd if=/dev/zero of=/asmdisks/disk3 bs=1024k count=1000
dd if=/dev/zero of=/asmdisks/disk4 bs=1024k count=1000
dd if=/dev/zero of=/asmdisks/disk5 bs=1024k count=1000
我在这里生成了5个1GB的文件,并且全部用0来填充。losetup命令可以将这5个大文件‘变成‘5个本地磁盘。
losetup /dev/loop1 /asmdisks/disk1
losetup /dev/loop2 /asmdisks/disk2
losetup /dev/loop3 /asmdisks/disk3
losetup /dev/loop4 /asmdisks/disk4
losetup /dev/loop5 /asmdisks/disk5
现在就可以对这5个设备进行格式化了,使用任何一种我们喜欢的文件系统。

2. 安装ASM类库
ASM的安装需要Oracle提供的asm类库支持,可以在这里http://www.oracle.com/technology/tech/linux/asmlib/index.html 下载到。下载的时候注意自己机器的配置,用uname -a查看。
oracleasm-support.rpm
oracleasm-2.6.9-42-x86_64.EL.rpm
oracleasmlib.rpm
为了让机器每次重启的时候,都让系统自动加载ASM并配置好的权限,我们需要运行以下命令。
/etc/init.d/oracleasm configure
oracle
oinstall
y
y

3. 配置ASM磁盘组
/etc/init.d/oracleasm createdisk ASMD1 /dev/loop1
/etc/init.d/oracleasm createdisk ASMD2 /dev/loop2
/etc/init.d/oracleasm createdisk ASMD3 /dev/loop3
/etc/init.d/oracleasm createdisk ASMD4 /dev/loop4
/etc/init.d/oracleasm createdisk ASMD5 /dev/loop5

4. 创建ASM实例
传统的逻辑卷都有逻辑卷管理器,ASM的逻辑卷管理器就是一种Oracle实例,但是一种特殊的实例。没有buffer cache和log buffer因为它不需要open一个database。ASM实例有large pool和shared pool以及一些特殊的后台进程
以root身份运行
/oracle/10g/bin/localconfig add

换成oracle用户,编辑+ASM实例的参数文件
INSTANCE_TYPE=ASM
DB_UNIQUE_NAME=+ASM
LARGE_POOL_SIZE=8M
ASM_DISKSTRING=ORCL:*

启动ASM实例
export ORACLE_SID=+ASM
sqlplus / as sysdba

create diskgroup DGROUP1 normal redundancy
disk 'ORCL:ASMD1','ORCL:ASMD2','ORCL:ASMD3',
'ORCL:ASMD4','ORCL:ASMD5';

在/etc/rc.local中加入如下内容:
/sbin/losetup /dev/loop1 /asmdisks/disk1
/sbin/losetup /dev/loop2 /asmdisks/disk2
/sbin/losetup /dev/loop3 /asmdisks/disk3
/sbin/losetup /dev/loop4 /asmdisks/disk4
/sbin/losetup /dev/loop5 /asmdisks/disk5
/etc/init.d/oracleasm createdisk ASMD1 /dev/loop1
/etc/init.d/oracleasm createdisk ASMD2 /dev/loop2
/etc/init.d/oracleasm createdisk ASMD3 /dev/loop3
/etc/init.d/oracleasm createdisk ASMD4 /dev/loop4
/etc/init.d/oracleasm createdisk ASMD5 /dev/loop5

5. 创建数据库
编辑参数文件init.ora
db_name=smart
sga_target=128M
db_create_file_dest=+DGROUP1
这里要注意,sga的不能太小,否则在创建数据库的时候会出现shared pool太小的错误。设置db_create_file_dest说明我们使用了OMF,Oracle Managed Files。
sqlplus “/ as sysdba”
create spfile from pfile;
shutdown immediate
startup nomount
create database;
create temporary tablespace temp;
create undo tablespace undotbs1;
@?/rdbms/admin/catalog
@?/rdbms/admin/catproc
alter database default temporary tablespace temp;
alter system set undo_tablespace=undotbs1 scope=spfile;
alter system set undo_management=auto scope=spfile;
startup force

6. 维护ASM
select name from v$datafile;
create tablespace DATA;
alter database datafile '+DGROUP1/smart/datafile/undotbs1.262.591694817' resize 120m;
alter database datafile '+DGROUP1/smart/datafile/undotbs1.262.591694817' autoextend off;
alter database datafile '+DGROUP1/smart/datafile/undotbs1.262.591694817' autoextend on next 10m;

7. 维护ASM文件
export ORACLE_SID=+ASM
asmcmd
添加ASM文件
$ su - root
# dd if=/dev/zero of=/asmdisks/disk6 bs=1024k count=1000
# /sbin/losetup /dev/loop6 /asmdisks/disk6
# /etc/init.d/oracleasm createdisk ASMD6 /dev/loop6

alter diskgroup DGROUP1 add disk 'ORCL:ASMD6';
alter diskgroup dgroup1 drop disk asmd6;

自我感觉,ASM就是一个专门为Oracle服务的,支持Oracle集群的软Raid。

参考 http://www.dizwell.com/prod/node/34

Monday, May 7, 2007

CLOB,LONG,NCLOB在SQL*PLUS的显示长度

SQL> SELECT DBMS_METADATA.GET_DDL('TABLE','BLANK') FROM DUAL;

DBMS_METADATA.GET_DDL('TABLE','BLANK')
--------------------------------------------------------------------------------

  CREATE TABLE "TEST"."BLANK"
   (    "A" VARCHAR2(100)
   ) PCTFREE 10 PCTUSED 4


SQL> SET LONG 2000
SQL> SELECT DBMS_METADATA.GET_DDL('TABLE','BLANK') FROM DUAL;

DBMS_METADATA.GET_DDL('TABLE','BLANK')
--------------------------------------------------------------------------------

  CREATE TABLE "TEST"."BLANK"
   (    "A" VARCHAR2(100)
   ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRAN
S 255 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEX
TENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS
1 BUFFER_POOL DEFAULT)
  TABLESPACE "USERS"


DBMS_METADATA.GET_DDL('TABLE','BLANK')
--------------------------------------------------------------------------------


SQL>

Sunday, May 6, 2007

Physical Standby Database Creation and Simple Management

Compared with RAC environment, standby database is much less complicated to set up.
A process of standby database creation generally contains these steps:
  1.  Force logging on primary database
  2.  Enable primary archive log mode
  3.  Generate pfile and shutdown primary database
  4.  Transport data files to standby node
  5.  Prepare both primary and standby parameter files
  6.  Standby instance service and password file creation
  7.  Set ORACLE_SID variable properly
  8.  Configure listeners and TNS names for both kind of nodes
  9.  Standby database control file generation
  10.  Startups

Here come more detailed processes.
1. Force logging on primary database
Force logging makes database running in logging-everything state, and by pass nologging clause.
  SQL> ALTER DATABASE FORCE LOGGING;

2. Enable primary archive log mode
Archive log mode is required to primary node but this is not prerequisite of standby nodes.
  SQL> SHUTDOWN IMMEDIATE
  SQL> STARTUP MOUNT
  SQL> ALTER DATABASE ARCHIVELOG;
  SQL> ALTER DATABASE OPEN;

3. Generate pfile and shutdown primary database
  SQL> CREATE PFILE=’D:\INITSMART.ORA’ FROM SPFILE;
  SQL> SHUTDOWN IMMEDIATE

4. Transport data files to standby node
Here you could make use of OS utilities to copy data files from primary node to standby nodes.

5. Prepare both primary and standby parameter files
Parameter file configuration is key step of the whole standby environment set up. Each node should have known others’ name, archive destination, path name convert method and how many processes serve for log archiving etc. Open pfile which I took from step 3, and add it with entries like this:

DB_NAME='smart'
DB_UNIQUE_NAME='smart'
LOG_ARCHIVE_CONFIG='DG_CONFIG=(smart,stb)'
LOG_ARCHIVE_DEST_1=
 'LOCATION=E:\oracle\product\10.2.0\oradata\smart
  VALID_FOR=(ALL_LOGFILES,ALL_ROLES)
  DB_UNIQUE_NAME=smart'
LOG_ARCHIVE_DEST_2=
 'SERVICE=stb LGWR ASYNC
  VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) 
  DB_UNIQUE_NAME=stb'
LOG_ARCHIVE_DEST_STATE_1=ENABLE
LOG_ARCHIVE_DEST_STATE_2=ENABLE
*.remote_login_passwordfile='EXCLUSIVE'
LOG_ARCHIVE_FORMAT=%t_%s_%r.arc
LOG_ARCHIVE_MAX_PROCESSES=30

FAL_SERVER=stb
FAL_CLIENT=smart
DB_FILE_NAME_CONVERT='stb','smart'
LOG_FILE_NAME_CONVERT='F:\oracle\product\10.2.0\oradata\stb\','E:\oracle\product\10.2.0\oradata\smart\'
STANDBY_FILE_MANAGEMENT=AUTO

On stb node, the scenario is quite similar but we still need some modification to show the critical difference.

DN_NAME='smart'
DB_UNIQUE_NAME='stb'
LOG_ARCHIVE_CONFIG='DG_CONFIG=(smart,stb)'
LOG_ARCHIVE_DEST_1=
 'LOCATION=F:\oracle\product\10.2.0\oradata\stb
  VALID_FOR=(ALL_LOGFILES,ALL_ROLES)
  DB_UNIQUE_NAME=stb'
LOG_ARCHIVE_DEST_2=
 'SERVICE=smart LGWR ASYNC
  VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) 
  DB_UNIQUE_NAME=smart'
LOG_ARCHIVE_DEST_STATE_1=ENABLE
LOG_ARCHIVE_DEST_STATE_2=ENABLE
*.remote_login_passwordfile='EXCLUSIVE'
LOG_ARCHIVE_FORMAT=%t_%s_%r.arc
LOG_ARCHIVE_MAX_PROCESSES=30

FAL_SERVER=smart
FAL_CLIENT=stb
DB_FILE_NAME_CONVERT='smart','stb'
LOG_FILE_NAME_CONVERT='E:\oracle\product\10.2.0\oradata\smart','F:\oracle\product\10.2.0\oradata\stb'
STANDBY_FILE_MANAGEMENT=AUTO

6. Standby instance service and password file creation
On windows platform, an instance service and password file will be required.
F:\ORACLE\PRODUCT\9.2\DATABASE\> ORADIM –NEW –SID STB –INTPWD ORACLE –STARTMODE M
On platform other than windows, you will also need password file to permit other nodes in standby environment to access local database with sys privilege.
[oracle@database dbs]$ orapwd file=PWDstb.ora password=oracle entries=20 force=y
I once forgot to generate a password file for the “stb” node with the same sys password on “smart”, then “smart” node failed to coordinate with “stb” even it tried thousands times before I shut it down.

7. Set ORACLE_SID variable properly
Windows:
C:\> set oracle_sid=stb
UNIX:
$export ORACLE_SID=STB

8. Configure listeners and TNS names for both kind of nodes
Listener.ora example:
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = F:\oracle\product\10.2.0\db_1)
      (PROGRAM = extproc)
    )
    (SID_DESC =
      (GLOBAL_DBNAME = whole)
      (ORACLE_HOME = F:\oracle\product\10.2.0\db_1)
      (SID_NAME = whole)
    )
    (SID_DESC =
      (GLOBAL_DBNAME = stb)
      (ORACLE_HOME = F:\oracle\product\10.2.0\db_1)
      (SID_NAME = stb)
    )
  )

C:\> lsnrctl stop
C:\> lsnrctl start

Modify tnsnames.ora and tnsping each other to make sure the oracle net service running okay.

9. Standby database control file generation
On the primary database.
  SQL> STARTUP MOUNT PFILE=’INITSMART.ORA’
  SQL> ALTER DATABASE CREATE STANDBY DATABASE CONTROLFILE AS ‘D:\CONTROL01.CTL’;
  SQL> ALTER DATABASE OPEN;

10. Startups
Copy the standby control file to stb node and:
  SQL> STARTUP MOUNT PFILE=’INITSTB.ORA’
  SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

Check out the result of our configuration on primary node with such command:
  SQL> ALTER SYSTEM SWITCH LOGFILE;
See if standby nodes have newly create archive log file.
  SQL> SELECT SEQUENCE# FROM V$ARCHIVED_LOG;

On the circumstance of primary node crash, we need a capable and functional database to take over the task as soon as possible. So, the first step is to finish managed recovery mode.
  SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE FINISH;
  SQL> ALTER DATABASE ACTIVATE STANDBY DATABASE;
  SQL> SHUTDOWN IMMEDIATE
  Cold backup here.
  SQL> STARTUP

On the circumstance to open the standby database in read-only mode, in order to query something in the stand by database, we need these steps to achieve our goal.
  SQL> RECOVER CANCEL / RECOVER MANAGED STANDBY DATABASE CANCEL;
  SQL> ALTER DATABASE OPEN READ ONLY;
  Bring back standby database to manual or managed recovery mode.
  SQL> RECOVER STANDBY DATABASE / RECOVER MANAGED STANDBY DATABASE TIME OUT 15;

Manual switch to standby database:
  Current primary node to standby node:
  SQL> ALTER DATABASE COMMIT TO SWITCHOVER TO PHYSICAL STANDBY;
  SQL> SHUTDOWN IMMEDIATE
  SQL> STARTUP MOUNT
  SQL> ALTER DATABASE MOUNT STANDBY DATABASE;
  SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;

  Current standby node to primary node:
  SQL> ALTER DATABASE TO SWITCHOVER TO PRIMARY;
  SQL> SHUTDOWN IMMEDIATE
  SQL> STARTUP
  SQL> ALTER SYSTEM SWITCH LOGFILE;

Thursday, May 3, 2007

TNS-12541

OS:Windows XP pro
Oracle: 10.2.0.1 64bit

listener中

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
    )
  )

其他机器用tnsping这台机器的话,会得到TNS-12541错误,no listener。
用netstat -an发现
TCP    127.0.0.1:1521    0.0.0.0:0    LISTENING
远程机器telnet 192.168.1.8 1521无法连接。

HOST要配置成机器名,才能避免这样的错误。

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = linux)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
    )
  )

这个时候
TCP    0.0.0.0:1521    0.0.0.0:0    LISTENING

折腾了我一个下午啊,thanks acterm。

浅谈Linux与Oracle的锁(未完成)

作者:feelfall
出处:feelfall.blogspot.com
转载时请保留作者和出处。

还是由于人懒,这篇文章没有写完。有兴趣再回头研究的时候,我会把这篇文章写完的。

信号量是一种描述共享资源的方法。
信号量分两种,一种是binary semaphore,一种counting semaphore。
在操作系统中,它是一种进程间通信(IPC)的重要手段。

锁是一种序列化机制,实现并发控制的一种手段,它强制那些使用资源的实体(如线程、进程)遵守某些规范(authorized or not. etc)。
锁从强制性分,有两种,一种是advisory lock(也称协作锁),一种是mandatory lock(强制锁)。
使用协作锁,控制权交由程序员来控制,进程或线程之间需要默契配合。这种锁不会防止程序员破坏自己的数据,使数据不一致。说白了,这种锁由user mode processes控制。
强制锁是内核控制检查的锁,这种锁一定会保证其约束条件。比如io scheduler调度不过来了,bio队列已满。
那么用户程序是不会在这个时候从操作系统得到资源的,必须被挂起。
锁从读取类型来分,也分两种,一种是shared lock,一种是exclusive lock。什么作用,这里不赘述了。

一个binary semaphore就可以是一个最简单的锁。
通常,锁是要求硬件支持的,以完成原子操作。
在多处理器的环境中,为了保证原子性,这些操作由处理器的特殊指令来实现,例如test-and-set,fetch-and-add或者是compare-and-swap。
可以防止interrupt破坏atomic operation。
嗯,是不是想起了oracle中的latch了?操作系统中是spin lock,oracle中是latch,目的差不多,防止并发修改,都是抢的。
用的cpu指令就是test-and-set,这是硬件提供的最底层的原子化操作。

现在说一下锁的粒度。
锁的粒度是指lock锁了多少资源。
锁粒度太小,会导致lock overhead。系统这个时候疲于应付反复initialize和destroy locks(内存资源)。用的锁越多,这个问题就越凸显。
粒度太大,会导致锁竞争。

信号量和锁之间是什么关系呢?

当进程试图访问一个被信号量保护的资源的时候,进程被挂起(进入sleep状态)。注意,申请使用信号量的函数都要是可以sleep的(中断和可延后程序就不行)。
当所需的信号量被释放,对应进程就会进入runnable状态,随时可以调度运行。
从Linux的角度看,序列化设备有spin lock,semaphore,(还有interrupt和softirq)。
从Oracle的角度看,序列化设备有latch lock和enqueue lock。latch使用test and set或者compare and swap,


先来简单看一下Linux的spin和semaphore结构。
------------------
|spinlock_types.h|
------------------
typedef struct {
  unsigned int slock;
} raw_spinlock_t;

typedef struct {
  raw_spinlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
  unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
  unsigned int magic, owner_cpu;
  void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
  struct lockdep_map dep_map;
#endif
} spinlock_t;

--------
|wait.h|
--------
struct __wait_queue_head {
  spinlock_t lock;
  struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;

----------
|atomic.h|
----------
typedef struct { volatile int counter; } atomic_t;

-------------
|semaphore.h|
-------------
struct semaphore {
  atomic_t count;
  int sleepers; 等待此信号量的进程数
  wait_queue_head_t wait; 等待进程队列
};


我们再来看一下linux中spin的函数。(片段)

-----------------------------------------
|linux-2.6.20.1/arch/s390/lib/spinlock.c|
-----------------------------------------
int spin_retry = 1000;

static inline void _raw_yield(void)
{
  if (MACHINE_HAS_DIAG44)
    asm volatile("diag 0,0,0x44");
}

static inline void _raw_yield_cpu(int cpu)
{
  if (MACHINE_HAS_DIAG9C)
    asm volatile("diag %0,0,0x9c"
           : : "d" (__cpu_logical_map[cpu]));
  else
    _raw_yield();
}

void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
{
  int count = spin_retry;
  unsigned int cpu = ~smp_processor_id();

  while (1) {
    if (count-- <= 0) {
      unsigned int owner = lp->owner_cpu;
      if (owner != 0)
        _raw_yield_cpu(~owner);
      count = spin_retry;
    }
    if (__raw_spin_is_locked(lp))
      continue;
    if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
      lp->owner_pc = pc;
      return;
    }
  }
}

int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
{
  unsigned int cpu = ~smp_processor_id();
  int count;

  for (count = spin_retry; count > 0; count--) {
    if (__raw_spin_is_locked(lp))
      continue;
    if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
      lp->owner_pc = pc;
      return 1;
    }
  }
  return 0;
}

void _raw_spin_relax(raw_spinlock_t *lock)
{
  unsigned int cpu = lock->owner_cpu;
  if (cpu != 0)
    _raw_yield_cpu(~cpu);
}

void _raw_read_lock_wait(raw_rwlock_t *rw)
{
  unsigned int old;
  int count = spin_retry;

  while (1) {
    if (count-- <= 0) {
      _raw_yield();
      count = spin_retry;
    }
    if (!__raw_read_can_lock(rw))
      continue;
    old = rw->lock & 0x7fffffffU;
    if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
      return;
  }
}

int _raw_read_trylock_retry(raw_rwlock_t *rw)
{
  unsigned int old;
  int count = spin_retry;

  while (count-- > 0) {
    if (!__raw_read_can_lock(rw))
      continue;
    old = rw->lock & 0x7fffffffU;
    if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
      return 1;
  }
  return 0;
}

void _raw_write_lock_wait(raw_rwlock_t *rw)
{
  int count = spin_retry;

  while (1) {
    if (count-- <= 0) {
      _raw_yield();
      count = spin_retry;
    }
    if (!__raw_write_can_lock(rw))
      continue;
    if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
      return;
  }
}

int _raw_write_trylock_retry(raw_rwlock_t *rw)
{
  int count = spin_retry;

  while (count-- > 0) {
    if (!__raw_write_can_lock(rw))
      continue;
    if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
      return 1;
  }
  return 0;
}

这里使用了compare and swap指令。spin_retry也是可以调整的。


用下面这个命令查看semaphore的使用情况。
# ipcs -s

------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0xd9895640 229376     oracle    640        154

一般来说结构越复杂,管理起来就越麻烦,相应的开销就越大。
然而对于不同的应用类型,比如一个只使用0.1ms的资源和一个要使用30s的资源,它们使用的序列化设备就应该不一样。
前者用spin,后者用semaphore。(注意到volatile没有?其实semaphore的count是受cpu的原子操作指令保护的)

Oracle的enqueue其实就是advisory lock方式(让oracle构筑自己的进程之间的序列化机制,kernel不会去强行干预),它使用semaphore来进行控制消息的传递。
比如LGWR在没有等到自己的semaphore的时候处于sleep状态。当得到自己的semaphore时LGWR开始干活,写出在线日志buffer。
这里稍微扯远点,当发生log file sync的时候,这里其实不是Oracle的锁的直接作用结果,而是系统的mandatory lock的间接产物,最终反映成log file sync。
首先,磁盘没有返回'写完成'的中断信号,OS的kernel级写线程的调度数量达到了上限,不允许用户进程再往里面塞bio,这时是mandatory lock。
ps:还有几种情况没有说,不把问题扯的太远,先说到这里,只是提一个不同lock mode,以后我还会写相关文章的。

在Linux上安装oracle的时候,我们通常要配置一下kernel的参数,其中就有shared memory也有semaphore相关的参数需要调整。

SHMMAX: 定义单个共享内存段的最大值。这只是一个上界值,如果使用时超过了这个值,那么会被分成多段。

SHMALL 可用共享内存的总数量(字节或者页面) 如果是字节,就和 SHMMAX 一样;如果是页面,ceil(SHMMAX/PAGE_SIZE) 

*SEMMSL:定义一个semaphore set中的semaphore数量上限。system v ipc中不是一个一个获取semaphore的,当然了,你可以获取只包含一个semaphore的semaphore set,it's up to you。
上面看到semaphore arrays的结果就是一个semaphore set。oracle的每个instance都需要一个semaphore set。
每个instance要求这个内核参数至少等于oracle允许的进程数(oracle参数文件中的processes)。

*SEMMNI:定义系统中一共可以有多少个semaphore set。有什么用呢?
你要是想在一个机器上启动两个oracle instance,那么仅就oracle来说,这个数值就至少要为2(当然还可能有其他的应用需要semaphore set,而不仅是oracle)。
如果你在一个机器上启动了多个instance,那么你ipcs -s的时候,看到的条目就是多个了。

*SEMMNS:定义系统中允许的semaphore数量的最大值。这个就不用解释了吧。

*SEMOPM:定义每个semop()系统调用所允许完成的操作。前面这句话肯定没有说清楚问题:)。
这么说吧,你的进程申请资源的时候可以一下申请多种资源,对应的就是几个semaphore。
semop系统调用就是申请资源用的,SEMOPM这个内核参数就是限定semop这个玩意儿一次可以操作(修改)多少个semaphore。

带*的由kernel.sem 250 32000 100 128 in /etc/sysctl.conf
means SEMMSL, SEMMNS, SEMOPM, and SEMMNI.

SEMVMX:定义......回到上面的struct semaphore,这里限定的就是count的最大值。也就是semaphore反映的资源数上限。

SEMMNU:定义系统中semaphore undo structrue的数量。当进程意外终止时,这种回滚结构可以保护相应的资源。SEMMNU这个参数值最好大于系统可能的最大进程数。

Oracle's latches and enqueues

latch:栓。
latch和spin的设计目标是一样的,都是以对象被锁定时间不长为前提的。
latch保护SGA里那些不能被并发修改的数据(排他的)。通常每种结构只需要一个latch就够了。
所以latch通常不被用来做shared access。
当处理器A持有某个资源的ltach,处理器B就不可以去使用这个资源。(有例外,不讲例外:D)
但是这个时候处理器B不会善罢甘休,它会不停的去test and set,试图得到这个资源。
为了不让B永远试下去,它进行test and set的次数是被限制的,由_SPIN_COUNT隐含参数确定(和linux中的spin_retry差不多)。
达到这个次数后,运行在B上的进程会去休息会儿。
休息多久呢?这由一个指数后退算法(这让我想起了上学时模拟的CSMA/CD)加参数_MAX_EXPONENTIAL_SLEEP来确定,
如果这个process还有别的latch,那么综合考虑,参数使用_MAX_SLEEP_HOLDING_LATCH。

我机器上的配置情况如下:
select b.KSPPINM as name,a.ksppstvl as value,b.KSPPDESC as description
  from X$KSPPCV a, X$KSPPI b
  where a.indx=b.indx and b.ksppinm = '_spin_count'

NAME                 VALUE      DESCRIPTION
-------------------- ---------- ----------------------------------------
_spin_count          2000       Amount to spin waiting for a latch


select b.KSPPINM as name,a.ksppstvl as value,b.KSPPDESC as description
  from X$KSPPCV a, X$KSPPI b
  where a.indx=b.indx and b.ksppinm = '_max_exponential_sleep'

NAME                           VALUE      DESCRIPTION
------------------------------ ---------- ----------------------------------------
_max_exponential_sleep         0          max sleep during exponential backoff


select b.KSPPINM as name,a.ksppstvl as value,b.KSPPDESC as description
  from X$KSPPCV a, X$KSPPI b
  where a.indx=b.indx and b.ksppinm = '_max_sleep_holding_latch'

NAME                           VALUE      DESCRIPTION
------------------------------ ---------- ----------------------------------------
_max_sleep_holding_latch       4          max time to sleep while holding a latch


latch的类型和开机后的统计结果可以从v$latch看。

现在的问题是,latch设计之初的确是认为被锁了的资源会马上释放。而且栓等待的时间不会很长。
但是,总有事与愿违的时候。
万一有些latch(long wait latch)的确要等一个比较长的时间的时间,那么怎么办呢?
那就可以当成队列锁来管理,这里叫latch wait posting,使用了semaphore进行管理。
如果一种latch适用latch wait posting,那么当要使用这种latch的进程由于争抢latch失败时,这个进程首先会把自己放入一个等待队列。
而当持有相应资源的进程释放latch的时候,等待进程会得到原先持有那个latch的进程的通知,从而立即进入runnable状态。
这个过程是一个再次争抢的过程,也就是说被挂起进程再次争抢相应latch。

(为什么设计之初没有直接用队列锁呢?是由于从统计的角度看,这种latch大部分时候可以通过争抢来获得,而在比较少的情况下稍长。)
那么,哪些latch在sleep的时候可以被当成队列锁(也就是用semaphore)来管理呢?
oracle 8i中有一个参数,_LATCH_WAIT_POSTING,它可以来调整适用latch wait posting的范围。
_LATCH_WAIT_POSTING有三个取值:
_LATCH_WAIT_POSTING=0,所有latch都适用latch wait posting。
_LATCH_WAIT_POSTING=1,enqueue hash chains latch,shared pool latch,library cache latch这三种latch适用。
_LATCH_WAIT_POSTING=2,所有latch都适用latch wait posting。
从9i开始,_LATCH_WAIT_POSTING这个参数没有了。但是latch wait posting这种机制却没有消失。
只不过是不让用户自行调整罢了。
你可以这样查看有哪些long wait latch:
select * from v$latch where waiters_woken>0;
系统只有在运行一段时间后才能看见所有的long wait latch,因为v$latch视图反映的是latch的统计结果。


latch可以分成三种:
child latch, parent latch, solitary latch
当latch保护的是一个结构中的子结构的时候,这种latch叫child latch。
从v$latch_parent视图中可以看见child latch的统计结果。
而同一种child latch会有一个parent latch。
没有child latch的parent latch称作solitary latch。
v$latch_children视图当中包含了parent latch和solitary latch的统计结果。

前面我们提到过的_spin_count参数可以调整一个进程每一次的争抢次数。但是这种调整的影响是全局的。
9i中采取了更为精细的做法,它相当于给用户提供8个可以单独调整的spin count。

SMART>select indx, spin, yield, waittime from x$ksllclass;

      INDX       SPIN      YIELD   WAITTIME
---------- ---------- ---------- ----------
         0      16000          0          1
         1      16000          0          1
         2      16000          0          1
         3      16000          0          1
         4      16000          0          1
         5      16000          0          1
         6      16000          0          1
         7      16000          0          1

已选择8行。

其中的每一行都与init.ora参数文件当中的_LATCH_CLASS_n相对应。
如果你觉得哪些latch需要稍短或稍长的spin count,那你就可以使用这些设备。
举个例子,我们现在的cache buffers chains latches的sleep时间过长,给cpu造成比较严重的负担。
我们决定将cache buffers chains latches的spin count单独调整,使之有别于全局的spin count。

SMART>select latch#, name from v$latchname where name = 'cache buffers chains';

    LATCH# NAME
---------- ------------------------------
        97 cache buffers chains

修改参数文件之前,先来看一下我使用的参数文件和类型。

SMART>show parameter spfile

NAME                                 TYPE                   VALUE
------------------------------------ ---------------------- ------------------------------
spfile                               string                 %ORACLE_HOME%\DATABASE\SPFILE%
                                                            ORACLE_SID%.ORA

此处得知,我使用的是spfile而不是pfile,那么我就要先从spfile生成一个pfile。

SMART>create pfile='init_new.ora' from spfile;

文件已创建。

接下来我们在参数文件当中加入:
*._latch_class_5 = "1000"  #将latch class 5的spin count设置成1000
*._latch_classes = "97:5"    #将97号latch的spin count绑定到latch class 5

shutdown后,再次启动oracle instance。

SMART> startup nomount pfile=d:\oracle\ora92\database\init_new.ora
ORACLE 例程已经启动。

Total System Global Area  135338868 bytes
Fixed Size                   453492 bytes
Variable Size             109051904 bytes
Database Buffers           25165824 bytes
Redo Buffers                 667648 bytes
SMART> alter database mount;

数据库已更改。

SMART> alter database open;

数据库已更改。

SMART> select indx, spin, yield, waittime from   x$ksllclass;

      INDX       SPIN      YIELD   WAITTIME
---------- ---------- ---------- ----------
         0      16000          0          1
         1      16000          0          1
         2      16000          0          1
         3      16000          0          1
         4      16000          0          1
         5       1000          0          1
         6      16000          0          1
         7      16000          0          1

已选择8行。

SMART> select a.kslldnam, b.kslltnum, b.class_ksllt
  2  from   x$kslld a, x$ksllt b
  3  where  a.kslldadr = b.addr
  4  and    b.class_ksllt > 0;

KSLLDNAM                         KSLLTNUM CLASS_KSLLT
------------------------------ ---------- -----------
process allocation                      3           2
cache buffers chains                   97           5

latch会不会引起死锁?
会!
所以oracle将进程获取latch的方式分为willing-to-wait和no-wait。
当进程要获取的latch超过一个的时候,这些latch是按顺序获取的。
那么这个顺序又是什么呢?
表示这个顺序的是一个介于0到15的数,用2个字节的位图来表示。
 0: 0000 0000 0000 0000
 1: 0000 0000 0000 0001
 2: 0000 0000 0000 0010
 3: 0000 0000 0000 0100
    ...
14: 0010 0000 0000 0000
15: 0100 0000 0000 0000
系统中,每一个latch都有一个这样的数,来表示latch的level。
如果一个进程以willing to wait模式试图获取一个latch(假设这个latch为A,level为 n),那么系统会首先确保这个进程没有持有level大于等于n的latch。
这个latch level可以从X$KSLLD内部视图的KSLLDLVL看到。
X$KSLLD  : [K]ernel [S]ervice [L]atch [L]ock [D]escriptor
KSLLDLVL : [K]ernel [S]ervice [L]atch [L]ock [D]escriptor [L]atch Le[V]e[L]
SMART>desc x$kslld;
 名称                    是否为空? 类型
 ----------------------- -------- ---------------

 ADDR                             RAW(4)
 INDX                             NUMBER
 INST_ID                          NUMBER
 KSLLDNAM                         VARCHAR2(64)
 KSLLDADR                         RAW(4)
 KSLLDLVL                         NUMBER

欲获取high level latch的进程在sleep阶段可能仍然会持有low level latch,从而使得需要low level latch的进程更加激烈的竞争。
low level latch可能会被长时间持有。
可以从v$latch视图的waits_holding_latch列得到相关的信息。
当这一字段所反映的情况十分糟糕的时候,那么需要dba进行干预。

如果当一个进程需要获取小于等于level n的latch时,采用willing to wait模式可能会引起死锁。
如果进程成功获取latch,没有死锁问题。
如果进程获得latch失败,那么它会释放掉自己的high level latches,然后立即以正确的顺序重新获取一遍latch。
这就是no wait模式了。

现在开始说一下enqueue lock。
Enqueue Lock是由Oracle Kernel Enqueue Service layer (KSQ)来负责管理的。

行锁(row level lock)
这里我们主要使用oracle的trace文件来进行分析。
开启两个session,我们这里称sesion A和session B。
session A:

SMART>create table t(a char(10), b int);

表已创建。

SMART>insert into t values('aaa',111);

已创建 1 行。

SMART>insert into t values('bbb',222);

已创建 1 行。

SMART>commit;

提交完成。

SMART>select file_id,block_id from dba_extents where owner=user and segment_name='T';

   FILE_ID   BLOCK_ID
---------- ----------
         1      50649

SMART>alter system dump datafile 1 block 50650; /*要比BLOCK_ID大一个block号*/

系统已更改。

SMART>select p.spid from v$process p, v$session s,
  2  (select sid from v$mystat where rownum<2) m
  3  where s.paddr=p.addr and s.sid=m.sid;

SPID
------------------------
2628

打开udump\demo_ora_2628.ora文件。

/*
我们这里只看transaction layer(KTB)和data layer(KD)的部分。
*/
Block header dump:  0x0040c5da
 Object id on Block? Y
 seg/obj: 0x75d9  csc: 0x00.16809e3  itc: 2  flg: O  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0003.000.00000114  0x00800036.0036.35  --U-    2  fsc 0x0000.01680a2d
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

上面两行是数据块的事物槽,每一行叫做一个ITL(Interested Transaction List) slot。

Itl:事物槽编号。
Xid:事物编号,transaction id。
Uba:Undo block address。
Flag:事物状态标志。
    ---- 事物处于活动状态中,或者提交后直接clean out了。
    C--- 已提交,锁被clean out了。
    -B-- (我不知道这个标志是做什么用的)
    --U- 已提交(也许很久之前提交的),需要clean out。
    ---T 事物在last full cleanout时仍然active。
Lck:这个事物锁了多少行数据。
Scn/Fsc: SCN or Free space credit。如果事物提交了,那么SCN表示commit SCN或者是SCN的上界(这和SCN的计算有关系),
如果没有提交,那么这里的前2个字节表示的就是事物在此block中free(动词)的字节数。


data_block_dump,data header at 0x306105c
===============
tsiz: 0x1fa0
hsiz: 0x16
pbl: 0x0306105c
bdba: 0x0040c5da
     76543210
flag=--------
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x1f7c
avsp=0x1f66
tosp=0x1f66
0xe:pti[0]  nrow=2  offs=0
0x12:pri[0]  offs=0x1f8e
0x14:pri[1]  offs=0x1f7c
block_row_dump:                                 <----数据
tab 0, row 0, @0x1f8e
tl: 18 fb: --H-FL-- lb: 0x1  cc: 2              <----看见这里的lb没有?0x1就是第一个ITL。
col  0: [10]  61 61 61 20 20 20 20 20 20 20     <----col 0占10个字节(跟我们定义的一样),数据如何存的以后讲。
col  1: [ 3]  c2 02 0c                          <----col 1所占的字节数暂时为3,因为int类型实际的存储是可变的
tab 0, row 1, @0x1f7c
tl: 18 fb: --H-FL-- lb: 0x1  cc: 2
col  0: [10]  62 62 62 20 20 20 20 20 20 20
col  1: [ 3]  c2 03 17
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 50650 maxblk 50650

我们现在打开session B
SMART>update t set b=10 where a='bbb';

已更新 1 行。

SMART>alter system dump datafile 1 block 50650;

系统已更改。

暂时没有提交,再看dump文件的结果。

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0003.000.00000114  0x00800036.0036.35  C---    0  scn 0x0000.01680a2d
0x02   0x0007.026.0000011c  0x008002a8.0032.25  ----    1  fsc 0x0001.00000000
 
block_row_dump:
tab 0, row 0, @0x1f8e
tl: 18 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [10]  61 61 61 20 20 20 20 20 20 20
col  1: [ 3]  c2 02 0c
tab 0, row 1, @0x1f6b
tl: 17 fb: --H-FL-- lb: 0x2  cc: 2
col  0: [10]  62 62 62 20 20 20 20 20 20 20
col  1: [ 2]  c1 0b
end_of_block_dump
End dump data blocks tsn: 0 file#: 1 minblk 50650 maxblk 50650

v$lock, v$transaction, v$transaction_enqueue 中大家自己去看吧。

session B提交.
SMART>commit;

提交完成。

SMART>alter system dump datafile 1 block 50650;

系统已更改。

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0003.000.00000114  0x00800036.0036.35  C---    0  scn 0x0000.01680a2d
0x02   0x0007.026.0000011c  0x008002a8.0032.25  --U-    1  fsc 0x0001.01686955

block_row_dump:
tab 0, row 0, @0x1f8e
tl: 18 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [10]  61 61 61 20 20 20 20 20 20 20
col  1: [ 3]  c2 02 0c
tab 0, row 1, @0x1f6b
tl: 17 fb: --H-FL-- lb: 0x2  cc: 2
col  0: [10]  62 62 62 20 20 20 20 20 20 20
col  1: [ 2]  c1 0b
end_of_block_dump

行锁到此结束,下面讲讲buffer lock。
row level lock是用来控制磁盘上的并发读写的设备,而buffer lock是用来控制buffer cache中的block的并发读写。
以后讲等待事件的时候再仔细梳理一遍buffer lock。总而言之,buffer lock是一种应用在SGA的buffer cache中的lock。

字典锁(Data Dictionary Lock)
看名字就知道这种锁是用来保护什么的了。
当数据字典被引用的时候,数据字典是不能被删除的,其定义也不能被修改。
当系统对sql statement进行语法分析,语义分析,安全检查,生成备用查询计划,评估查询计划,定义输出格式,返回结果...
全部步骤完成之后,相应的字典锁才可以被释放。
一些锁可以被用来锁字典。比如row cache enqueue lock,library cache pins,DML lock。

锁模式
被锁的对象可以分成混合对象和简单对象。
复杂对象就好比一个table和table当中的rows,简单对象就好比buffer cache。

简单对象适合用下面三种锁:
Exclusive:排他锁,完全杜绝concurrent access。
Shared:共享锁,可以concurrent inspect/read,但是不可以修改。
Null:Steve Adams的书上说,这种锁啊,是当替换符用的。
如果一个会话cache了一个对象的信息,即便这个资源没有处于活动状态会话也会持有一个对应的null lock。
Null mode lock不会限制并发,但是当这个资源不再有效的时候,null lock会像trigger一样,通知会话清理相关cache。

除了上面三种锁之外,还有三种锁适用于混合对象。
Sub-shared:这种锁就是对混合对象的子对象分别使用共享锁,这样做可以提供更多的灵活性。
比如以部分区域可以共享,剩余的区域要被独占。
Sub-exclusive:与前者相反。
Shared-sub-exclusive:当会话需要一个混合对象的部分排他锁和整体共享锁时,就使用这种锁模式。

这六种锁模式适用于local lock和instance lock(也就是集群环境中,用以节点之间协作的enqueue)。

下面这张表给出了各种锁类型在dump文件中的缩写和等待事件中的数字编号。



那些锁是相互兼容的也十分重要,这里给出这种关系的矩阵。



Oracle运行时就是依据上面这个表来判定会话应该得到锁还是被enqueue。

Oracle Kernel Enqueue Service layer (KSQ)负责管理所有enqueue。
会话在请求资源的时候,首先会去请求这个资源结构的锁。
在得到锁之前,系统会给这个资源当中用来描述锁的链表(引用的容器)加入一个锁的引用。
Enqueue resource可以从X$KSQRS (kernel service enqueue resource)或者V$RESOURCE试图当中看到。
SQL> select * from v$resource;

ADDR     TY        ID1        ID2
-------- -- ---------- ----------
6F644CE8 XR          4          0
6F644D40 TS          3          1
6F644EF8 CF          0          0
6F645058 RT          1          0
6F6450B0 RS         25          1
6F645538 MR          3          0
6F645590 MR          4          0
6F645698 MR          1          0
6F6456F0 MR          2          0
6F645748 MR        201          0
6F645A08 PW          1          0
6F646468 TA          6          1

(刚启动,还没有积攒起数据,嘿嘿)
Oracle 10g中V$EVENT_NAME试图里的PARAMETER2和PARAMETER3给出了ID1和ID2的含义。
在10g以前,这些含义没有给出,但是大家可以在网上找到。
TY: 指锁类型
ID1和ID2根据TY的不同,其含义也不同。
参数ENQUEUE_RESOURCES和_ENQUEUE_LOCKS定义了SGA中最多能有多少enqueue resource structure
每个enqueue resource structure都有三种锁引用的容器,分别是owner,waiter,convertor。

enqueue lock
select * from v$enqueue_lock;
给出了会话ID,锁类型,ID1和ID2,锁模式,请求模式,当前模式时间和blocking flag
查看TX锁和TM锁
select * from x$ktcxb where  KTCXBLKP in (select kaddr from v$lock where type = 'TX');
select * from x$ktadm where  KSQLKADR in (select kaddr from v$lock where type = 'TM');

Session A
SQL> test/test
已连接。
SQL> update blank set a='v' where a='cc';

已更新 1 行。

Session B
SQL> test/test
已连接。
SQL> update blank set a='dd';

Session C
SQL> select sid, event, p1, p1raw,
  2  chr(bitand(P1,-16777216)/16777215)||chr(bitand(P1,16711680)/65535) type,
  3  mod(P1, 16) "MODE" from v$session_wait where  event like '%row lock%';

       SID EVENT                                  P1 P1RAW    TYPE       MODE
---------- ------------------------------ ---------- -------- ---- ----------
        48 enq: TX - row lock contention  1415053318 54580006 TX            6

SQL>

select * from v$enqueue_stat


参考文献:

http://www.ixora.com.au/q+a/datablock.htm

《Oracle8i Internal Services For waits, latches, locks》

《Oracle Wait Interface: A Practical Guide to Performance Diagnostics & Tuning》

《Expert Oracle Database Architechture Oracle 9i and 10g Programming Techniques and Solutions》

http://www.revealnet.com/newsletter-v6/0905_E.htm

http://groups.google.com/group/Oracle-Internal/browse_thread/thread/5864abd39b3f8ffb

Wednesday, May 2, 2007

手动创建数据库


DBCA是好,但是作为DBA,必须要了解数据库创建的过程。

mkdir F:\oracle\product\10.2.0\flash_recovery_area
mkdir F:\oracle\product\10.2.0\oradata\replica
mkdir F:\oracle\product\10.2.0\admin\replica\bdump
mkdir F:\oracle\product\10.2.0\admin\replica\cdump
mkdir F:\oracle\product\10.2.0\admin\replica\udump
mkdir F:\oracle\product\10.2.0\admin\replica\scripts

#################init.ora###########################
nls_language="SIMPLIFIED CHINESE"
nls_territory="CHINA"
sga_target=167772160
job_queue_processes=10
dispatchers="(PROTOCOL=TCP) (SERVICE=replicaXDB)"
compatible=10.2.0.1.0
audit_file_dest=F:\oracle\product\10.2.0\admin\replica\adump
remote_login_passwordfile=EXCLUSIVE
pga_aggregate_target=16777216
db_domain=""
db_name=replica
control_files=("F:\oracle\product\10.2.0\oradata\replica\control01.ctl", "F:\oracle\product\10.2.0\oradata\replica\control02.ctl", "F:\oracle\product\10.2.0\oradata\replica\control03.ctl")
db_create_file_dest=F:\oracle\product\10.2.0\oradata
db_recovery_file_dest=F:\oracle\product\10.2.0\flash_recovery_area
db_recovery_file_dest_size=2147483648
open_cursors=300
undo_management=AUTO
undo_tablespace=UNDOTBS1
background_dump_dest=F:\oracle\product\10.2.0\admin\replica\bdump
core_dump_dest=F:\oracle\product\10.2.0\admin\replica\cdump
user_dump_dest=F:\oracle\product\10.2.0\admin\replica\udump
processes=150
db_block_size=8192
db_file_multiblock_read_count=16
####################################################

set ORACLE_SID=replica

oradim -new -sid replica -intpwd oracle -startmode M

sqlplus /nolog

conn / as sysdba
set echo on
spool F:\oracle\product\10.2.0\admin\replica\scripts\CreateDB.log
startup nomount pfile="F:\oracle\product\10.2.0\admin\replica\scripts\init.ora";

create spfile= FROM pfile='F:\oracle\product\10.2.0\admin\replica\scripts\init.ora';

CREATE DATABASE "REPLICA"
MAXINSTANCES 8
MAXLOGHISTORY 1
MAXLOGFILES 16
MAXDATAFILES 100
DATAFILE 'F:\oracle\product\10.2.0\oradata\replica\system.dbf'
        SIZE 300M
        AUTOEXTEND ON
        NEXT 10240K
        MAXSIZE UNLIMITED
        EXTENT MANAGEMENT LOCAL
SYSAUX DATAFILE 'F:\oracle\product\10.2.0\oradata\replica\sysaux.dbf'
        SIZE 120M
        AUTOEXTEND ON
        NEXT 10240K
        MAXSIZE UNLIMITED
SMALLFILE DEFAULT TEMPORARY TABLESPACE TEMP
        TEMPFILE 'F:\oracle\product\10.2.0\oradata\replica\temp.dbf'
        SIZE 20M AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED
SMALLFILE UNDO TABLESPACE "UNDOTBS1"
        DATAFILE 'F:\oracle\product\10.2.0\oradata\replica\undo.dbf'
        SIZE 200M AUTOEXTEND ON NEXT 5120K MAXSIZE UNLIMITED
CHARACTER SET AL32UTF8
NATIONAL CHARACTER SET AL16UTF16
LOGFILE GROUP 1 ('F:\oracle\product\10.2.0\oradata\replica\redo1.rdo') SIZE 51200K,
GROUP 2 ('F:\oracle\product\10.2.0\oradata\replica\redo2.rdo') SIZE 51200K,
GROUP 3 ('F:\oracle\product\10.2.0\oradata\replica\redo3.rdo') SIZE 51200K
USER SYS IDENTIFIED BY ORACLE USER SYSTEM IDENTIFIED BY ORACLE;

CREATE SMALLFILE TABLESPACE "USERS" LOGGING
        DATAFILE 'F:\oracle\product\10.2.0\oradata\replica\user.dbf'
        SIZE 5M
        AUTOEXTEND ON
        NEXT  1280K
        MAXSIZE UNLIMITED
        EXTENT MANAGEMENT LOCAL
        SEGMENT SPACE MANAGEMENT AUTO;
ALTER DATABASE DEFAULT TABLESPACE "USERS";

@F:\oracle\product\10.2.0\db_1\rdbms\admin\catalog.sql; --*
@F:\oracle\product\10.2.0\db_1\rdbms\admin\catblock.sql;
@F:\oracle\product\10.2.0\db_1\rdbms\admin\catproc.sql; --*
@F:\oracle\product\10.2.0\db_1\rdbms\admin\catoctk.sql;
@F:\oracle\product\10.2.0\db_1\rdbms\admin\owminst.plb;
@F:\oracle\product\10.2.0\db_1\rdbms\admin\catclust.sql; --RAC

conn system/oracle
@F:\oracle\product\10.2.0\db_1\sqlplus\admin\pupbld.sql;
conn system/oracle
@F:\oracle\product\10.2.0\db_1\sqlplus\admin\help\hlpbld.sql helpus.sql;

conn / as sysdba
@F:\oracle\product\10.2.0\db_1\javavm\install\initjvm.sql;
@F:\oracle\product\10.2.0\db_1\xdk\admin\initxml.sql;
@F:\oracle\product\10.2.0\db_1\xdk\admin\xmlja.sql;
@F:\oracle\product\10.2.0\db_1\rdbms\admin\catjava.sql;
@F:\oracle\product\10.2.0\db_1\rdbms\admin\catexf.sql;
--其它部件参看文档
spool off

shutdown immediate
conn / as sysdba
execute utl_recomp.recomp_serial(); --重新编译所有的objects


编辑listener.ora文件
SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_NAME=WHOLE)
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = F:\oracle\product\10.2.0\db_1)
      (PROGRAM = extproc)
    )
    (SID_DESC =
      (GLOBAL_DBNAME = replica)
      (ORACLE_HOME = F:\oracle\product\10.2.0\db_1)
      (SID_NAME = replica)
    )
  )

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
      (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))
    )
  )

cmd> lsnrctl reload