使用RMAN和Broker快速搭建DataGuard环境

使用RMAN和Broker快速搭建DataGuard环境
1. 不适合在生成环境中使用,如果生成环境中搭建dg的话推荐手动配置;
2. 实验环境:
1. 主库:
1. ip:192.168.10.11;
2. hostname:primary.snda.com;
2. 备库:
1. ip:192.168.10.12;
2. hostname:standby.snda.com;
3. 分别设置主库和备库的~/.bash_profile,$ORACLE_HOME/network/admin/listener.ora和$ORACLE_HOME/network/admin/tnsnames.ora文件;
4. 修改主库的系统参数,然后关闭数据库,启动到mount状态,并修改数据库为归档模式,并创建pfile;
5. 备份主库的数据文件和控制文件;
6. 拷贝主库的文件到备库;
7. 修改备库的pfile,创建spfile,并启动到nomount状态;
8. 使用rman恢复备库;
9. 主库备库分别添加Standby Redo Log Fiels;
10. 分别修改主库和备库的初始化参数:dg_broker_start;
11. 在任意一台机器上启动dgmgrl,并配置当前的broker环境;
12. 修改数据库为高可用模式;
13. SWITCHOVER和FAILOVER操作;
14. 切换数据库的状态为只读模式和在线接收日志状态;

— 主库和备库的~/.bash_profile文件内容;
ORACLE_SID=PROD
ORACLE_BASE=/u01/app/oracle
ORACLE_HOME=$ORACLE_BASE/product/10.2.0/db_1
PATH=/usr/sbin:$PATH
PATH=$ORACLE_HOME/bin:$PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib
CLASSPATH=$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib
export ORACLE_BASE ORACLE_HOME ORACLE_SID PATH LD_LIBRARY_PATH CLASSPATH

alias sqlplus=’rlwrap sqlplus’
alias rman=’rlwrap rman’
alias dgmgrl=’rlwrap dgmgrl’

— 主库的$ORACLE_HOME/network/admin/listener.ora文件内容,修改完成后运行lsnrctl start/reload重新加载监听文件;
LISTENER=
(DESCRIPTION=
(ADDRESS_LIST=
(ADDRESS=(PROTOCOL=tcp)(HOST=primary.snda.com)(PORT=1521))
)
)
SID_LIST_LISTENER=
(SID_LIST=
(SID_DESC=
(SID_NAME=PROD)
(ORACLE_HOME=/u01/app/oracle/product/10.2.0/db_1)
)
(SID_DESC=
(SID_NAME=PROD)
(ORACLE_HOME=/u01/app/oracle/product/10.2.0/db_1)
(GLOBAL_DBNAME=PROD_PRI_DGMGRL)
)
)

— 备库的$ORACLE_HOME/network/admin/listener.ora文件内容,修改完成后运行lsnrctl start/reload重新加载监听文件;
LISTENER=
(DESCRIPTION=
(ADDRESS_LIST=
(ADDRESS=(PROTOCOL=tcp)(HOST=standby.snda.com)(PORT=1521))
)
)
SID_LIST_LISTENER=
(SID_LIST=
(SID_DESC=
(SID_NAME=PROD)
(ORACLE_HOME=/u01/app/oracle/product/10.2.0/db_1)
)
(SID_DESC=
(SID_NAME=PROD)
(ORACLE_HOME=/u01/app/oracle/product/10.2.0/db_1)
(GLOBAL_DBNAME=PROD_SBY_DGMGRL)
)
)

— 主库和备库的$ORACLE_HOME/network/admin/tnsnames.ora文件
PROD_PRI=
(DESCRIPTION=
(ADDRESS=(PROTOCOL=tcp)(HOST=primary.snda.com)(PORT=1521))
(CONNECT_DATA=
(SERVICE_NAME=PROD)
(SERVER=DEDICATED)
)
)

PROD_SBY=
(DESCRIPTION=
(ADDRESS=(PROTOCOL=tcp)(HOST=standby.snda.com)(PORT=1521))
(CONNECT_DATA=
(SERVICE_NAME=PROD)
(SERVER=DEDICATED)
)
)

— 修改主库的系统参数,然后关闭数据库,启动到mount状态,并修改数据库为归档模式,并创建pfile;
ALTER SYSTEM SET db_unique_name=PROD_PRI scope=spfile;
ALTER SYSTEM SET db_recovery_file_dest_size=4G;
ALTER SYSTEM SET db_recovery_file_dest=’/u01/app/oracle/flash_recovery_area’;
ALTER SYSTEM SET log_archive_dest_1=’LOCATION=/u01/app/oracle/flash_recovery_area’;
ALTER SYSTEM SET log_archive_dest_2=”;
ALTER SYSTEM SET local_listener=”;
ALTER SYSTEM SET dispatchers=”;
ALTER SYSTEM SET standby_file_management=AUTO;

SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE FORCE LOGGING;
ALTER DATABASE ARCHIVELOG;
— ALTER DATABASE FLASHBACK ON;
ALTER DATABASE OPEN;
CREATE PFILE FROM SPFILE;

— 备份主库的数据文件和控制文件;
rman target /
BACKUP DATABASE FORMAT ‘/u01/app/oracle/flash_recovery_area/%U’;
BACKUP CURRENT CONTROLFILE FOR STANDBY FORMAT ‘/u01/app/oracle/flash_recovery_area/%U’;

— 拷贝主库的文件到备库;
scp /u01/app/oracle/flash_recovery_area/* oracle@standby.snda.com:/u01/app/oracle/flash_recovery_area/
scp $ORACLE_HOME/dbs/initPROD.ora oracle@standby.snda.com:$ORACLE_HOME/dbs/
scp $ORACLE_HOME/dbs/orapwPROD oracle@standby.snda.com:$ORACLE_HOME/dbs/

— 修改备库的pfile,创建spfile,并启动到nomount状态;
修改备库的参数文件,只修改db_unique_name=’PROD_SBY’即可;
CREATE SPFILE FROM PFILE;
STARTUP NOMOUNT;

— 使用rman恢复备库;
rman target sys/oracle@prod_pri auxiliary /
DUPLICATE TARGET DATABASE FOR STANDBY NOFILENAMECHECK;

— 主库备库分别添加Standby Redo Log Fiels;
ALTER DATABASE ADD STANDBY LOGFILE GROUP 4 (‘/u01/app/oracle/oradata/PROD/redo04.log’) SIZE 100M;
ALTER DATABASE ADD STANDBY LOGFILE GROUP 5 (‘/u01/app/oracle/oradata/PROD/redo05.log’) SIZE 100M;
ALTER DATABASE ADD STANDBY LOGFILE GROUP 6 (‘/u01/app/oracle/oradata/PROD/redo06.log’) SIZE 100M;
ALTER DATABASE ADD STANDBY LOGFILE GROUP 7 (‘/u01/app/oracle/oradata/PROD/redo07.log’) SIZE 100M;

— 分别修改主库备库的初始化参数;
ALTER SYSTEM SET dg_broker_start=TRUE;

— 在任意一台机器上启动dgmgrl,并配置当前的broker环境;
dgmgrl sys/oracle@prod_pri
CREATE CONFIGURATION DGCONFIG1 AS PRIMARY DATABASE IS PROD_PRI CONNECT IDENTIFIER IS PROD_PRI;
ADD DATABASE PROD_SBY AS CONNECT IDENTIFIER IS PROD_SBY MAINTAINED AS PHYSICAL;
ENABLE CONFIGURATION;
SHOW CONFIGURATION;

— 修改数据库为高可用的保护状态;
EDIT DATABASE PROD_PRI SET PROPERTY LogXptMode=’Sync’;
EDIT DATABASE PROD_SBY SET PROPERTY LogXptMode=’Sync’;
EDIT CONFIGURATION SET PROTECTION MODE AS MaxAvailability;

— 切换数据库的主备角色;
SWITCHOVER TO PROD_SBY;
SWITCHOVER TO PRDO_PRI;
SELECT PROTECTION_MODE, PROTECTION_LEVEL, DATABASE_ROLE, SWITCHOVER_STATUS FROM v$database;

— FAILOVER操作;
FAILOVER TO PROD_PRI;
FAILOVER TO PROD_SBY;

— 切换数据库的状态为只读模式和在线接收日志状态;
EDIT DATABASE PROD_SBY SET STATE=’READ-ONLY’;
EDIT DATABASE PROD_SBY SET STATE=’ONLINE’;

— 设置数据库的其它属性;
EDIT DATABASE db SET PROPERTY StandbyFileManagement=’AUTO’;
EDIT DATABASE db SET PROPERTY StandbyArchiveLocation=’/u01/app/oracle/flash_recovery_area’;

— 删除表空间和表空间所有的内容;
DROP TABLESPACE tbs INCLUDE CONTENTS CASCADE CONTRAINTS;

Oracle Cloud03-Oracle Compute Cloud Service快速实践

这是Oracle Cloud系列的第三篇文章,按照第一篇文章中的介绍申请试用账户,就从这一篇开始使用试用账户进行相关的操作和学习,这篇主要讲了:
1.如何创建Oracle Cloud实例;
2.如何进行网络配置;
3.如何进行实例磁盘扩容;
4.如何进行CPU/内存资源扩容;

Oracle Cloud 03-Oracle Compute Cloud Service快速实践

在VirtualBox中安装Oracle 12c RAC

1.实验环境:
    1.OS:Oracle Linux Server release 6.6;
    2.Oracle:12.1.0.2.0;
    3.Node1:
        1.hostname:node1.oracle.com;
        2.public ip:192.168.10.170(eth0);
        3.private ip:191.168.20.170(eth1);
        4.virtual ip:192.168.10.173;
    4.Node2:
        1.hostname:node2.oracle.com;
        2.public ip:192.168.10.171(eth0);
        3.private ip:191.168.20.171(eth1);
        4.virtual ip:192.168.10.174;
    5.SCAN IP:192.168.10.177/192.168.10.178/192.168.10.179;
2.配置网络环境,安装软件包并调整服务器的时间和参数:
    1.设置服务器名:hostname;
    2.修改/etc/hosts,/etc/sysconfig/network;
    3.使用ntp服务器保持时间同步;
    4.设置IP地址;
    5.配置DNS服务器,并修改/etc/resolv.conf配置文件;
    6.安装软件包:yum -y install binutils* compat-lib* gcc* glibc* ksh make* sysstat* unixODBC* libgcc* libstdc++* libaio* libXext* libXtst* libX11* libXau* libxcb* libXi*;
    7.分别修改/etc/sysctl.conf文件;
    8.分别修改/etc/security/limits.conf文件;
    9.修改/etc/pam.d/login文件;
    10.创建grid和oracle用户及添加相应的环境变量;
    11.关闭防火墙和SELinux;
3.使用udev创建共享磁盘;
4.安装GI;
    1.解压软件;
    2.安装cvu相关rpm包:rpm -ivh /tools/grid/rpm/cvuqdisk-1.0.9-1.rpm;
    3.安装前校验:/tools/grid/runcluvfy.sh stage -pre crsinst -n node1,node2 -verbose;
    4.最后检查资源状态:crsctl stat res -t;
5.使用asmca命令创建磁盘组;
    1.创建GI的时候已经创建了CRS磁盘组;
    2.创建DATA磁盘组;
    3.创建FRA磁盘组;
6.安装数据库软件;
7.安装数据库;
    1.查看资源状态:crsctl stat res -t;
    2.查看RAC数据库配置信息:srvctl config database -d ORCL/srvctl status database -d ORCL/srvctl status listener;
———————– 网络配置 ———————–
— 修改主机名;
hostname node1.oracle.com
hostname node2.oracle.com
— 修改/etc/hosts;
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# Public IP
192.168.10.170  node1.oracle.com        node1
192.168.10.171  node2.oracle.com        node2
# Private IP
192.168.20.170  node1-pri.oracle.com    node1-pri
192.168.20.171  node2-pri.oracle.com    node2-pri
# VIP
192.168.10.172  node1-vip.oracle.com    node1-vip
192.168.10.173  node2-vip.oracle.com    node2-vip
# Scan IP
192.168.10.177  rac-cluster-scan.oracle.com         rac-cluster-scan
#192.168.10.178 rac-cluster-scan.oracle.com         rac-cluster-scan
#192.168.10.179 rac-cluster-scan.oracle.com         rac-cluster-scan
# DNS Server
#192.168.10.180 rac-dns.oracle.com      rac-dns
— 修改/etc/sysconfig/network;
HOSTNAME=node1.oracle.com
HOSTNAME=node2.oracle.com
———————– 网络配置 ———————–
———————– 系统参数 ———————–
— 修改/etc/sysctl.conf文件;
fs.file-max = 6815744
kernel.sem = 250 32000 100 128
kernel.shmmni = 4096
kernel.shmall = 1073741824
kernel.shmmax = 4398046511104
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
fs.aio-max-nr = 1048576
net.ipv4.ip_local_port_range = 9000 65500
> sysctl -p;
— 修改/etc/security/limits.conf文件;
grid    soft    nproc   2047
grid    hard    nproc   16384
grid    soft    nofile  4096
grid    hard    nofile  65536
oracle  soft    nproc   2047
oracle  hard    nproc   16384
oracle  soft    nofile  4096
oracle  hard    nofile  65536
— 修改/etc/pam.d/login文件;
session required /lib/security/pam_limits.so
session required pam_limits.so
———————– 系统参数 ———————–
———————– 创建用户 ———————–
— 创建用户组;
groupadd -g 10001 oinstall
groupadd -g 10002 dba
groupadd -g 10003 oper
groupadd -g 10004 backupdba
groupadd -g 10005 dgdba
groupadd -g 10006 kmdba
groupadd -g 10007 asmdba
groupadd -g 10008 asmoper
groupadd -g 10009 asmadmin
— 创建用户;
useradd -u 10000 -g oinstall -G dba,oper,asmdba,backupdba,dgdba,kmdba oracle;
useradd -u 10001 -g oinstall -G dba,asmdba,asmoper,asmadmin grid;
— 创建软件目录;
mkdir -p /u01/app/grid;
mkdir -p /u01/app/12.1.0/grid;
mkdir -p /u01/app/oracle/product/12.1.0/db_1;
chown -R grid:oinstall /u01;
chown -R oracle:oinstall /u01/app/oracle;
chmod -R 775 /u01;
— 设置grid用户的环境变量.bash_profile
ORACLE_HOSTNAME=node1.oracle.com
ORACLE_SID=+ASM1
ORACLE_BASE=/u01/app/grid
ORACLE_HOME=/u01/app/12.1.0/grid
PATH=$ORACLE_HOME/bin:/usr/sbin:$PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:/usr/lib:/lib
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib
export ORACLE_HOSTNAME ORACLE_SID ORACLE_BASE ORACLE_HOME PATH LD_LIBRARY_PATH CLASSPATH
alias sqlplus=’rlwrap sqlplus’
— 设置oracle用户的环境变量.bash_profile
ORACLE_HOSTNAME=node1.oracle.com
ORACLE_SID=ORCL1
ORACLE_UNQNAME=ORCL
ORACLE_BASE=/u01/app/oracle
ORACLE_HOME=$ORACLE_BASE/product/12.1.0/db_1
PATH=$ORACLE_HOME/bin:/usr/sbin:$PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib
CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib
export ORACLE_HOSTNAME ORACLE_SID ORACLE_UNQNAME ORACLE_BASE ORACLE_HOME PATH LD_LIBRARY_PATH CLASSPATH
alias sqlplus=’rlwrap sqlplus’
———————– 创建用户 ———————–
———————– 创建共享磁盘 ———————–
— 在一个虚拟机中创建[固定大小]的虚拟磁盘;
— 然后在[管理]->[虚拟介质管理]界面,修虚拟磁盘的类型为[可共享];
— 添加到另外的虚拟机中;
———————– 创建共享磁盘 ———————–
———————– 使用udev配置共享磁盘 ———————–
— 生成udev规则文件的脚本;
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z
do
echo “KERNEL==\”sd*\”, BUS==\”scsi\”, PROGRAM==\”/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/\$name\”, RESULT==\”`/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/sd$i`\”, NAME=\”asm-disk$i\”, OWNER=\”grid\”, GROUP=\”asmadmin\”, MODE=\”0660\””
done
— 检查是否安装udev;
rpm -qa | grep udev
— 添加规则文件vi /etc/udev/rules.d/99-oracle-asmdevices.rules;(内容可以通过脚本生成)
KERNEL==”sd*”, BUS==”scsi”, PROGRAM==”/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/$name”, RESULT==”1ATA_VBOX_HARDDISK_VBab81d7dc-431ca37f”, NAME=”asm-crs”, OWNER=”grid”, GROUP=”asmadmin”, MODE=”0660″
KERNEL==”sd*”, BUS==”scsi”, PROGRAM==”/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/$name”, RESULT==”1ATA_VBOX_HARDDISK_VBe8fa478f-cd38bd32″, NAME=”asm-data1″, OWNER=”grid”, GROUP=”asmadmin”, MODE=”0660″
KERNEL==”sd*”, BUS==”scsi”, PROGRAM==”/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/$name”, RESULT==”1ATA_VBOX_HARDDISK_VB57dac3e5-ff6636ce”, NAME=”asm-data2″, OWNER=”grid”, GROUP=”asmadmin”, MODE=”0660″
KERNEL==”sd*”, BUS==”scsi”, PROGRAM==”/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/$name”, RESULT==”1ATA_VBOX_HARDDISK_VB04158991-1baaa75c”, NAME=”asm-data3″, OWNER=”grid”, GROUP=”asmadmin”, MODE=”0660″
KERNEL==”sd*”, BUS==”scsi”, PROGRAM==”/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/$name”, RESULT==”1ATA_VBOX_HARDDISK_VB389c5a94-92168d11″, NAME=”asm-fra1″, OWNER=”grid”, GROUP=”asmadmin”, MODE=”0660″
KERNEL==”sd*”, BUS==”scsi”, PROGRAM==”/sbin/scsi_id –whitelisted –replace-whitespace –device=/dev/$name”, RESULT==”1ATA_VBOX_HARDDISK_VBbfb07df0-3eca3187″, NAME=”asm-fra2″, OWNER=”grid”, GROUP=”asmadmin”, MODE=”0660″
— 将该规则文件拷贝到其他节点上;
— 在所有节点上启动udev服务;
/sbin/start_udev
— 检查文件;
ll /dev/
———————– 使用udev配置共享磁盘 ———————–
———————– RAC的启动和关闭顺序 ———————–
1.关闭RAC:
    1.关闭数据库:停止所有节点上的实例[oracle@node1 ~]$ srvctl stop database -d ORCL;
    2.停止OHAS(Oracle High Availability Services):[root@node1 ~]# $GRID_HOME/crsctl stop has -f;
    3.停止集群服务:root@node1 ~]# $GRID_HOME/crsctl stop cluster [-all];
2.启动RAC,默认开机会自启动,手工启动的顺序如下:
    1.启动集群:root@node1 ~]# $GRID_HOME/crsctl start cluster [-all];
    2.启动OHAS:root@node1 ~]# $GRID_HOME/crsctl start has;
    3.启动数据库:[oracle@node1 ~]$ srvctl start database -d ORCL;
———————– RAC的启动和关闭顺序 ———————–

Oracle11g备库报ORA-00367和ORA-19527的问题

首先看一下alter.log文件中的错误信息(片段):
Tue Dec 22 06:00:47 2015
SRL log 13 needs clearing because log has not been created
Errors in file /app/sungard/oracle/diag/rdbms/futures8_standby/futures8/trace/futures8_rfs_29400.trc:
ORA-00367: checksum error in log file header
ORA-00315: log 13 of thread 0, wrong thread # 1 in header
ORA-00312: online log 13 thread 0: ‘/ora_data/oradata/futures8_standby/redo03.log’
SRL log 14 needs clearing because log has not been created
Errors in file /app/sungard/oracle/diag/rdbms/futures8_standby/futures8/trace/futures8_rfs_29400.trc:
ORA-00367: checksum error in log file header
ORA-00315: log 14 of thread 0, wrong thread # 1 in header
ORA-00312: online log 14 thread 0: ‘/ora_data/oradata/futures8_standby/redo04.log’

Oracle官方给出的引起这三个错的原因和处理的办法:
—————————————————————————————-
Error: ORA-00367
Cause: The file header for the redo log contains a checksum that does not match
the value calculated from the file header as read from disk. This means
the file header is corrupted
Action: Find the correct file and try again.
—————————————————————————————-
Error: ORA-00315
Cause: The online log is corrupted or is an old version.
Action: Find and install correct version of log or reset logs.
—————————————————————————————-
Error: ORA-00312
Cause: The control file change sequence number in the log file is greater
than the number in the control file. This implies that the wrong control
file is being used. Note that repeatedly causing this error can make it
stop happening without correcting the real problem.
Action: Use the current control file or do backup control file recovery to make the
control file current. Be sure to follow all restrictions on doing a backup
control file recovery.
—————————————————————————————-

根据官方提示可以看出,是因为控制文件中记录的SCN小于日志文件头部记录的SCN引起的,从而需要通过还原最新的控制文件来解决;这种方式是非常麻烦的,还需要还原数据文件并以resetlogs的方式打开;
除了以上办法,还可以通过清空日志文件的方式,来同步控制文件和日志头SCN:
ALTER DATABASE CLEAR LOGFILE GROUP 13;

命令执行之后会报另外的错误:
ORA-19527: physical standby redo log must be renamed
ORA-00312: online log 13 thread 0: ‘/ora_data/oradata/futures8_standby/redo03.log’

这个错误是10gR2之后功能的增强引起的:在做主备切换的时候,需要将备库的联机日志文件清除(CLEAR ONLINE REDO LOGFILE),为了加快SWITCHOVER的速度,Oracle10gR2之后在将备库置于MANGED STANDBY状态的时候就提前将这个CLEAR的动作做了,这个想法是好的,只是实现有点糟糕,然后会在alert.log文件里记录错误一堆错误;
This is in fact an Enhancement to the Data Guard Technology introduced in 10.2.0.
The Goal here is to improve speed of Switchover and Failover. In previous Versions a Role Transition would require to clear the Online Redo Logfiles before it can become a Primary Database. Now we attempt to clear the Online Redo Logfiles when starting Managed Recovery.
If the Files exist then they will be cleared, but if they do not exist we report the Error, attempts to create the Online Redo Logfiles and starts Recovery. Even if this is not possible because of different Structure and log_file_name_convert is not set, MRP does not fail; it only raises these Errors.
As an extra Enhancement if the Online Redologs do exist you must specify the log_file_name_convert Parameter even if there is no difference in the Name. This has been implemented to reduce the chances that the Primary Online Redologs are cleared when MRP starts. It is the equivalent of asking – Are you sure you want the logs to be called this….
If the log_file_name_convert parameter is not set then the ORA-19527 is reported and the log file is not cleared at this time..
Solution to stop both of these errors is to ensure log_file_name_convert is set correctly. If the File Structure is the same on the Primary and Standby Database you can set log_file_name_convert to a dummy Value;

好在给出了解决办法,只需要设置LOG_FILE_NAME_CONVERT参数即可,即便是主备目录是一致的,那么完整的解决办法如下:
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
ALTER SYSTEM SET LOG_FILE_NAME_CONVERT=’/ora_data/oradata/futures8/’,’/ora_data/oradata/futures8/’,’/ora_data/oradata/futures8_standby/’,’/ora_data/oradata/futures8_standby/’ SCOPE=SPFILE;
STARTUP IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE CLEAR LOGFILE GROUP 13;
ALTER DATABASE CLEAR LOGFILE GROUP 14;
ALTER DATABASE CLEAR LOGFILE GROUP 15;
ALTER DATABASE CLEAR LOGFILE GROUP 16;
ALTER DATABASE CLEAR LOGFILE GROUP 17;
ALTER DATABASE CLEAR LOGFILE GROUP 18;
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE [USING CURRENT LOGFILE] DISCONNECT FROM SESSION;
参考文档:Note 1532566.1, Note 352879.1

DataGuard主从不同步案例处理(ORA-01274)

问题描述:
1.Oracle11.2.0.3 DataGuard环境,主库在做表空间扩容时添加了很多数据文件,但是备机空间不足,导致文件创建失败,进而无法正常同步;
2.在备库的alert文件中报ORA-01274的错误,提示创建失败的文件在控制文件中被重命名为$ORACLE_HOME/dbs/UNNAMED0048,而且MRP进程中止;

1358F88A-E519-4A0C-9CD4-9B109BE8CB4D

05F609D1-1955-449E-BF42-CE5A7639D32F

处理步骤:
1.修改备机管理模式为手动:ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT = MANUAL;
2.创建丢失文件:ALTER DATABASE CREATE DATAFILE ‘/oracle/product/11.2.0/db_1/dbs/UNNAMED00048’ AS ‘/oradata/htcwdb/NNC_DATA0306.dbf’;
3.修改备机管理模式为自动:ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT = AUTO;
4.恢复日志[并从主机接收日志]:RECOVER STANDBY DATABASE [DISCONNECT FROM SESSION];或者
5.接受日志并实时应用:ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;

dbms_stats.import_table_stats不可以把统计信息导给别的表

今天在itpub看到一个问题 说是使用dbms_stats.import_table_stats并不会导入统计信息 然后做了一个实验如下

SQL> create table test as select * from dba_objects;

Table created.

SQL> create index idx_test on test(object_id);

Index created.

SQL> begin
dbms_stats.gather_table_stats(ownname          => ‘SCOTT’,
tabname          => ‘TEST’,
estimate_percent => 100,
degree           => 2,
cascade          => true);
end;  2    3    4    5    6    7
8  /

PL/SQL procedure successfully completed.

SQL> create table test_temp as select * from test;

Table created.

SQL> create index idx_test_temp on test_temp(object_id);

Index created.

SQL> select table_name,
num_rows,
blocks,
empty_blocks,
avg_space,
avg_row_len,
sample_size
from user_tables
where table_name in (‘TEST’, ‘TEST_TEMP’);  2    3    4    5    6    7    8    9

TABLE_NAME                         NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE
—————————— ———- ———- ———— ———-
AVG_ROW_LEN SAMPLE_SIZE
———– ———–
TEST                                    75253        1098                0           0
97          75253

TEST_TEMP

SQL> begin
— dbms_stats.drop_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
dbms_stats.create_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
dbms_stats.export_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’,cascade => true);
dbms_stats.delete_table_stats(ownname=>’scott’,tabname=>’test_temp’);
dbms_stats.import_table_stats(ownname=>’scott’,tabname=>’test_temp’,stattab=>’stat_test_temp’);
end;  2    3    4    5    6    7
8  /

PL/SQL procedure successfully completed.

SQL> select table_name,
num_rows,
blocks,
empty_blocks,
avg_space,
avg_row_len,
sample_size
from user_tables
where table_name in (‘TEST’, ‘TEST_TEMP’);  2    3    4    5    6    7    8    9

TABLE_NAME                         NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE
—————————— ———- ———- ———— ———-
AVG_ROW_LEN SAMPLE_SIZE
———– ———–
TEST                                    75253        1098                0           0
97          75253

TEST_TEMP

以上是你的实验

再往下看

SQL> begin
dbms_stats.drop_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
dbms_stats.create_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
dbms_stats.export_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’,cascade => true);
dbms_stats.delete_table_stats(ownname=>’scott’,tabname=>’test’);
—  dbms_stats.import_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’);
end;  2    3    4    5    6    7
8  /

PL/SQL procedure successfully completed.

SQL> select table_name,
num_rows,
blocks,
empty_blocks,
avg_space,
avg_row_len,
sample_size
from user_tables
where table_name in (‘TEST’, ‘TEST_TEMP’);  2    3    4    5    6    7    8    9

TABLE_NAME                         NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE
—————————— ———- ———- ———— ———-
AVG_ROW_LEN SAMPLE_SIZE
———– ———–
TEST

TEST_TEMP

SQL> begin
— dbms_stats.drop_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
—  dbms_stats.create_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
–dbms_stats.export_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’,cascade => true);
—  dbms_stats.delete_table_stats(ownname=>’scott’,tabname=>’test’);
dbms_stats.import_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’);
end;  2    3    4    5    6    7
8  /

PL/SQL procedure successfully completed.

SQL> select table_name,
num_rows,
blocks,
empty_blocks,
avg_space,
avg_row_len,
sample_size
from user_tables
where table_name in (‘TEST’, ‘TEST_TEMP’);  2    3    4    5    6    7    8    9

TABLE_NAME                         NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE
—————————— ———- ———- ———— ———-
AVG_ROW_LEN SAMPLE_SIZE
———– ———–
TEST                                    75253        1098                0           0
97          75253

TEST_TEMP

由此可见这个功能不是用于把一张表的统计信息给别的表 而是用于发生了进行不同统计信息的性能测试
我们再看一个实验

先备份

SQL> begin
dbms_stats.drop_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
dbms_stats.create_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
–dbms_stats.export_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’,cascade => true);
—  dbms_stats.delete_table_stats(ownname=>’scott’,tabname=>’test’);
–dbms_stats.import_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’);
end;  2    3    4    5    6    7
8  /

PL/SQL procedure successfully completed.

SQL> drop table test purge;

Table dropped.

SQL> create table test as select * from dba_objects;

Table created.

SQL> create index idx_test on test(object_id);

Index created.

SQL> select table_name,
num_rows,
blocks,
empty_blocks,
avg_space,
avg_row_len,
sample_size
from user_tables
where table_name in (‘TEST’, ‘TEST_TEMP’);  2    3    4    5    6    7    8    9

TABLE_NAME                         NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE
—————————— ———- ———- ———— ———-
AVG_ROW_LEN SAMPLE_SIZE
———– ———–
TEST

TEST_TEMP

SQL> begin
–dbms_stats.drop_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
— dbms_stats.create_stat_table(ownname=>’scott’,stattab=>’stat_test_temp’);
–dbms_stats.export_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’,cascade => true);
—  dbms_stats.delete_table_stats(ownname=>’scott’,tabname=>’test’);
dbms_stats.import_table_stats(ownname=>’scott’,tabname=>’test’,stattab=>’stat_test_temp’);
end;  2    3    4    5    6    7
8  /

PL/SQL procedure successfully completed.

SQL> select table_name,
num_rows,
blocks,
empty_blocks,
avg_space,
avg_row_len,
sample_size
from user_tables
where table_name in (‘TEST’, ‘TEST_TEMP’);  2    3    4    5    6    7    8    9

TABLE_NAME                         NUM_ROWS     BLOCKS EMPTY_BLOCKS  AVG_SPACE
—————————— ———- ———- ———— ———-
AVG_ROW_LEN SAMPLE_SIZE
———– ———–
TEST

TEST_TEMP

SecureFile LOBs and BasicFile LOBs

oracle11g推出以后有了一种新的LOBS的存储模式叫做SecureFile LOBs 与之区别 把以前使用的叫做basicFile Lobs
根据官方文档上的说法 secure是哪哪都好。提供了压缩 重复消除 加密等新的功能 但是basicFile Lobs依然是default的
secureFime的用法是通过在LOB存储子句后添加SECUREFILE关键字来创建
最简单的一种写法:
SQL> CREATE TABLE images (
2 id NUMBER,
3 i_data CLOB
4 )
5 LOB(i_data) STORE AS BASICFILE;

Table created

SQL> CREATE TABLE images2 (id NUMBER,
2 i_data CLOB
3 )
4 LOB(i_data) STORE AS SECUREFILE;

Table created.
———————————————————————————
Securefile列标明了是否为SecureFile类型的LOB
SQL> SELECT TABLE_NAME,SEGMENT_NAME,INDEX_NAME,SECUREFILE FROM DBA_LOBS WHERE TABLE_NAME like ‘IMAGES%’;

TABLE_NAME SEGMENT_NAME
—————————— ——————————
INDEX_NAME SEC
—————————— —
IMAGES SYS_LOB0000076951C00002$$
SYS_IL0000076951C00002$$ NO

IMAGES2 SYS_LOB0000076948C00002$$
SYS_IL0000076948C00002$$ YES
Securefile

使用Securefile LOB的表也是自动生成LOB segment和LOB index的。
但是此时LOB index只有在使用重复消除功能时才会使用,在其他情况下不会使用

SQL> CREATE TABLE images2 (id NUMBER,
2 i_data CLOB
3 )
4 LOB(i_data) STORE AS SECUREFILE
5 ;
CREATE TABLE images2 (id NUMBER,
*
ERROR at line 1:
ORA-43853: SECUREFILE lobs cannot be used in non-ASSM tablespace “SYSTEM”
要注意,Securefile LOB只能在ASSM的表空间(自动管理的表空间)里创建,
不过既然从9i起ASSM表空间就是默认设置了,一般这里不会有多大问题。
只是要求SecureLOB所在的LOB列数据需要存放在ASSM表空间中,而包含LOB列的那个表可以不是
CREATE TABLE images2 (id NUMBER,i_data CLOB) LOB(i_data) STORE AS SECUREFILE (tablespace ucjmh);
SQL> conn / as sysdba
Connected.
SQL> CREATE TABLE images2 (id NUMBER,i_data CLOB) LOB(i_data) STORE AS SECUREFILE (tablespace ucjmh);

Table created.

————————————————————————————————–
SQL> show parameter DB_SECUREFILE

NAME TYPE VALUE
———————————— ———– ——————————
db_securefile string PERMITTED

这个值的取值范围有:
DB_SECUREFILE = { NEVER | PERMITTED | ALWAYS | IGNORE }
PERMITTED 是默认的 就是当你指定是什么的时候就是什么
FORCE 是ORA-43853的来源 意思就是不管你是否指定用SecureFile 创建的时候都是用Securefile 如果不是在ASSM的表空间 那么就报ORA-43853
ALWAYS 意思就是不管你是否指定用SecureFile 创建的时候都是用Securefile 但是如果你是非ASSM的表空间 那就是BASICFILE 如果非ASSM的时候你还显示的指定了用SecureFiLE 那也报43853
NEVER 是不管怎么样都是BasicFile 如果指定了一些加密或压缩之类的参数那么就报ORA-43853
IGNORE 是不管怎么样都是BasicFile 如果指定了一些加密或压缩之类的参数也不报错。

chunk:
在BasicFile的LOB中,Chunk的大小是一定的,最小跟DB Block的大小一样,最大为32KB
–一个chunk最多只保留一行LOB数据,也就是说,如果你设置了32K的CHUNK,但是如果LOB字段大小只有4K,也将占用32K的空间
而在SecureFile中,chunk的size是可变的,由Oracle自动动态分配,最小跟DB Block的大小一样,最大为64MB
–指定的值最好是数据库块的倍数,而且指定的值不能大于表空间区间中NEXT的值

当指定enable storage in row的时候,当lob size =4000 bytes的时候,将存储在lob段里面,其存储方式和表段存储方式完全不一样,使用的是chunk为最小单位的存储,没有行迁移和行链接的概念。
如果设置了enable storage in row 那么oracle会自动将小于4000bytes的数据存储在行内, 这是ORACLE的默认值,
对于大于4000字节的lob字段保存在lob段(同disable storage in row),在表段将保留36-84字节的控制信息。
对于disable storage in row,Oracle将lob字段分开保存在lob段中,而仅仅在行位置保留20字节的指针。
对于相当于disable storage in row的这部分(也就是单独保存在LOB段的这部分数据),UNDO仅仅是记录指针与相关lob索引改变,如果发生更新操作等DML操作,原始数据将保留在LOB段
DISABLE STORAGE IN ROW:如果DISABLE这个属性,那么lob数据会在行外存储,行内只存储该lob值得指针,而且这个属性在表
storage as(cache|nocahce)表示是否允许lob段经过buffer cache并缓存。默认是nocache,表示直接读与直接写,不经过数据库的data buffer。所以,默认情况下,对于单独保存在LOB段的这部分数据,在发生物理读的时候,是直接读,如direct path read (lob)

storage as(nocache logging |nocache nologging),logging/nologging属性只对nocache方式生效,默认是logging,如果是nologging方式,对于 保存在行外的log部分,在update等DML操作时将不记录redo日志

PCTVERSION integer、RETENTION:都是ORACLE用来管理LOB字段镜像数据的。在LOB 数据的更新过程中,
ORACLE没有用UNDO TABLESPACE空间,而是从LOB字段所在的表空间里划分一段空间来做镜像空间的,
这个空间的大小由PCTVERSION参数控制,默认值为10,代表划分表空间的10%作为镜像空间,
每个镜像空间的单元大小由CHUNK参数指定,pctversion可以使用在manual undo mode和automatic undo mode 环境中
retention应用了automatic undo mode中的undo_retention通过时间来管理lob镜像空间.
pctversion和retention不能同时被指定.建议数据库在automatic undo mode下使用retention参数

SecureFile的COMPRESS选项在表或分区一级上开启了对LOB内容的压缩,使用关键字MEDIUM和HIGH表示压缩的等级,
如果没有指定压缩等级,就默认为MEDIUM,对LOB内容进行压缩会增加系统开销,
因此使用高等级的压缩可能会对系统性能产生不良影响,SecureFile LOB的压缩功能不影响表压缩,反之亦然
SecureFile LOB的加密功能依赖于钱夹或硬件安全模型(HSM)掌管加密密钥,钱夹设置与透明数据加密(TDE)和表空间加密描述的一样,
因此在尝试下面的例子前先完成那两个实验。SecureFile的ENCRYPT选项执行块级别的LOB内容加密,
一个可选的USING子句定义了使用哪种加密算法(3DES168, AES128, AES192, 或AES256),默认使用AES192算法,
NO SALT选项对于SecureFile加密不可用,加密是应用在每一列上的,因此它会影响所有使用LOB的分区,DECRPT选项用于明确地阻止加密
加密是不受imp/exp或表空间传输支持的,因此必须使用impdp/exddp来传输数据

BasicFile和SecureFile LOB共享了部分基础的缓存和日志选项,常见的缓存选项有:
CACHE – LOB数据被放在缓冲区中。
CACHE READES – 仅读取LOB数据过程中它放在缓冲区中,写操作时不放进去。
NOCACHE – LOB数据不放在缓冲区中,这是BasicFile和SecureFile LOB的默认值。
基本的日志选项有:
LOGGING – 创建和修改LOB时产生完全重做日志,这是默认设置。
NOLOGGING – 操作不记录在重做日志中,因此不能恢复,在首次创建和巨大的载入过程中有用。
而且,SecureFile LOB还有一个日志选项FILESYSTEM_LIKE_LOGGING,只记录元数据,在出现故障后仍然允许段的恢复。
CACHE选项意味着LOGGING,因此你不能将CACHE与NOLOGGING或FILESYSTEM_LIKE_LOGGING合在一起使用。
如果要移动表
ALTER TABLE table_name LOB (lob_item) STORE AS [lob_segment]
(
TABLESPACE tablespace_name
(STORAGE…..)
ENABLE|DISABLE STORAGE IN ROW
CHUNK integer
PCTVERSION integer
RETENTION
FREEPOOLS integer
CACHE|NOCACHE|CACHE READS
INDEX lobindexname

(TABLESPACE tablesapce_name

((STORAGE…..))
)

Oracle Varray变量

[oracle@ucjmh ~]$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.3.0 Production on Tue Jul 7 09:01:40 2015

Copyright (c) 1982, 2011, Oracle. All rights reserved.

Connected to:

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 – Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> set serveroutput on

SQL> DECLARE

— declare fixed array

TYPE arry_num IS VARRAY(10) OF NUMBER;

arry_top arry_num;

v_n int;

BEGIN

— init array

arry_top := arry_num(1,2,3);

dbms_output.put_line(arry_top.LIMIT());

dbms_output.put_line(arry_top.count());

dbms_output.put_line(arry_top.FIRST());

–dbms_output.put_line(arry_top.NEXT());

— dbms_output.put_line(arry_top.PRIOR());

dbms_output.put_line(arry_top.LAST());

dbms_output.put_line(arry_top(2));

FOR I IN 1..arry_top.COUNT() LOOP

v_n:=arry_top(I);

dbms_output.put_line(v_n);

DBMS_OUTPUT.PUT_LINE(‘arry_top(‘||I||’)=’ || arry_top(I));

END LOOP;

END;

/

10

3

1

3

2

1

arry_top(1)=1

2

arry_top(2)=2

3

arry_top(3)=3

PL/SQL procedure successfully completed.

SQL>

声明和初始化VARRAY变量

你不可以直接声明一个VARRAY变量。必须先声明一个包含这个数组最大容量的类型:
1. TYPE MY_ARRAY_TYPE IS VARRAY(10) OF NUMBER;
然后,你就可以用这个类型声明VARRAY变量:
1. V MY_ARRAY_TYPE;
在你对这个数组进行操作以前,必须先初始化该数组。你既可以在声明它的时候对其初始化,也可以在声明后对其赋值。下面展示了在声明的同时对其进行初始化:
1. V MY_ARRAY_TYPE := MY_ARRAY_TYPE ();
从指定的条目处取值

把条目的数目作为下标。下标可以是返回整数值(该值小于或等于数组条目数)的任意表达式,如:
1. K := V(3); 2. I := 2; 3. L := V(I+1);
得到数组的容量

对VARRAY变量使用COUNT()方法。注意,你不需要指定圆括号,因为这个方法没有输入参数:
1. N_ENTRIES := V.COUNT();
这告诉你这个数组中正在使用的条目数。当VARRAY类型被声明的时候,其最大的容量也就被定义了。你可以用LIMIT()方法得到该容量:
1. ARRAY_CAPACITY := V.LIMIT();
遍历VARRAY中的值

你可以使用多种技术。最简单的是使用FOR循环:
1. FOR I IN 1..V.COUNT() LOOP 2. DBMS_OUTPUT.PUT_LINE(‘V(‘||I||’)=’ || V(I)); 3. END LOOP;
你也可以使用FIRST()和LAST()方法。FIRST()返回数组的第一个条目的下标(总是1),LAST()返回数组的最后一个条目的下标(与COUNT方法相同)。
1. FOR I IN V.FIRST()..V.LAST() LOOP 2. DBMS_OUTPUT.PUT_LINE(‘V(‘||I||’)=’ || V(I)); 3. END LOOP;
你也可以使用PRIOR(n)和NEXT(n)方法,这两个方法分别返回给定条目的前一个和后一个条目的下标。例如,下面的代码用来向后遍历整个数组:
1. I := V.COUNT(); 2. WHILE I IS NOT NULL LOOP 3. DBMS_OUTPUT.PUT_LINE(‘V(‘||I||’)=’ || V(I)); 4. I := V.PRIOR(I); 5. END LOOP;
PRIOR(n)和n-1是一样的,NEXT(n)和n+1是一样的,但是PRIOR(1)和NEXT(V.COUNT())则返回NULL。
对VARRAY的扩展

使用EXTEND(k)方法。这个方法可以在VARRAY的最后追加k个新的条目。如果k没有被指定,只增加一个条目。新增的条目没有值(默认为NULL),但是你可以对它们进行初始化。COUNT()和LAST()方法现在可以反映VARRAY新的容量。以下代码向数组中添加两个条目并对其进行初始化:
1. I := V.LAST(); 2. V.EXTEND(2); 3. V(I+1) := 5; 4. V(I+2) := 6;
注意,你对VARRAY的扩展不可以超过其最大容量(通过LIMIT()方法得到),且在对VARRAY扩展前必须要对其进行初始化。以下代码是无效的:
1. VT MY_ARRAY_TYPE; 2. VT.EXTEND(5);
下面的代码是有效的:
1. VT MY_ARRAY_TYPE; 2. VT := MY_ARRAY_TYPE(); 3. VT.EXTEND(5);
对VARRAY的缩减

使用TRIM(k)方法。这个方法在VARRAY的尾部删除最后k个条目。当k没有被指定时,删除最后一个条目。已被删除的条目的值将丢失。COUNT()和LAST()方法反映了新的容量。下面从VARRAY中删除最后一个条目:
1. V.TRIM;
你也可以用以下方式删除数组中的所有条目:
1. V.TRIM(V.COUNT());
或者用具有效果相同的DELETE()方法。该方法删除数组中的所有条目,并把其容量设置为0(也就是说,V.COUNT()现在的返回值为0)。
1. V.DELETE()

使用SQL实现对邮政编码分类规则

早晨在大阪工作的学长发信息过来要想用SQL实现对日本邮政编码分类的规则.本来学长只需要做概要设计即可,详细设计和开发都是外包给越南人做,但是担心越南的童鞋方法不能够满意,索性就直接把关键的步骤都自己实现掉,想想也是为了世界和平做了不少贡献;

规则是这样的:
1.日本邮编是7位的;
2.最终的结果集只需要两列(前缀 个数);
3.第一优先级是尾数为[00]的邮政编码;
4.第二优先级是前5位数字相同的邮政编码,只展现出现次数大于10次的结果,如果不足10次的邮政编码进入下一优先级统计;
5.第三优先级是前4位数字相同的邮政编码,规则同上;
6.第四优先级是前3位数字相同的邮政编码,规则同上;
7.第五优先级是剩余其它的邮政编码;

— 测试的数据,生成20W个邮政编码;
DROP TABLE TBPOSTTEST;
CREATE TABLE TBPOSTTEST AS
SELECT LPAD(ROUND(DBMS_RANDOM.VALUE (1, 9999999)) , 7, 0) postcode FROM DUAL
CONNECT BY LEVEL <= 200000;

— 实现的sql语句;
SELECT PREFIX, COUNT FROM (
WITH
P0P0 AS (SELECT ‘____00′ AS “PREFIX”, COUNT(*) c0 FROM TBPOSTTEST WHERE SUBSTR(postcode, LENGTH(postcode)-1) = ’00’),
P1P5 AS (SELECT SUBSTR(postcode, 0, 5) cp5, COUNT(*) c5 FROM TBPOSTTEST WHERE SUBSTR(postcode, LENGTH(postcode)-1) <> ’00’ GROUP BY SUBSTR(postcode, 0, 5)),
P2P4 AS (SELECT SUBSTR(cp5, 0, 4) cp4, SUM(c5) c4 FROM P1P5 WHERE c5 < 10 GROUP BY SUBSTR(cp5, 0, 4)),
P3P3 AS (SELECT SUBSTR(cp4, 0, 3) cp3, SUM(c4) c3 FROM P2P4 WHERE c4 < 10 GROUP BY SUBSTR(cp4, 0, 3))
SELECT ‘0’ AS “PRIORITY”, PREFIX, c0 AS “COUNT” FROM P0P0
UNION ALL
SELECT ‘1’, cp5 , c5 FROM P1P5 WHERE c5 >= 10
UNION ALL
SELECT ‘2’, cp4 , c4 FROM P2P4 WHERE c4 >= 10
UNION ALL
SELECT ‘3’, cp3 , c3 FROM P3P3 WHERE c3 >= 10
UNION ALL
SELECT ‘4’, ‘OTHER’ , SUM(c3) c2 FROM P3P3 WHERE c3 < 10)
ORDER BY PRIORITY;

— 测试的DEMO, 把条件改为大于2条;
INSERT INTO TBPOSTTEST VALUES(‘123400’);
INSERT INTO TBPOSTTEST VALUES(‘123500’);
INSERT INTO TBPOSTTEST VALUES(‘123450’);
INSERT INTO TBPOSTTEST VALUES(‘123451’);
INSERT INTO TBPOSTTEST VALUES(‘123452’);
INSERT INTO TBPOSTTEST VALUES(‘123453’);
INSERT INTO TBPOSTTEST VALUES(‘123454’);
INSERT INTO TBPOSTTEST VALUES(‘123444’);
INSERT INTO TBPOSTTEST VALUES(‘123555’);
INSERT INTO TBPOSTTEST VALUES(‘123566’);
INSERT INTO TBPOSTTEST VALUES(‘124444’);
COMMIT;

SELECT PREFIX, COUNT FROM (
WITH
P0P0 AS (SELECT ‘____00′ AS “PREFIX”, COUNT(*) c0 FROM TBPOSTTEST WHERE SUBSTR(postcode, LENGTH(postcode)-1) = ’00’),
P1P5 AS (SELECT SUBSTR(postcode, 0, 5) cp5, COUNT(*) c5 FROM TBPOSTTEST WHERE SUBSTR(postcode, LENGTH(postcode)-1) <> ’00’ GROUP BY SUBSTR(postcode, 0, 5)),
P2P4 AS (SELECT SUBSTR(cp5, 0, 4) cp4, SUM(c5) c4 FROM P1P5 WHERE c5 < 2 GROUP BY SUBSTR(cp5, 0, 4)),
P3P3 AS (SELECT SUBSTR(cp4, 0, 3) cp3, SUM(c4) c3 FROM P2P4 WHERE c4 < 2 GROUP BY SUBSTR(cp4, 0, 3))
SELECT ‘0’ AS “PRIORITY”, PREFIX, c0 AS “COUNT” FROM P0P0
UNION ALL
SELECT ‘1’, cp5 , c5 FROM P1P5 WHERE c5 >= 2
UNION ALL
SELECT ‘2’, cp4 , c4 FROM P2P4 WHERE c4 >= 2
UNION ALL
SELECT ‘3’, cp3 , c3 FROM P3P3 WHERE c3 >= 2
UNION ALL
SELECT ‘4’, ‘OTHER’ , SUM(c3) c2 FROM P3P3 WHERE c3 < 2)
ORDER BY PRIORITY;

— 测试结果;
PREFIX        COUNT
—————— ———-
____00               2
12345                 5
1235                   2
OTHER                2

创建带参数的视图

PROMPT CREATE OR REPLACE PACKAGE pkg_session

CREATE OR REPLACE PACKAGE pkg_session IS
TYPE parm_type IS TABLE OF varchar2(1000) index BY VARCHAR2(30);
PROCEDURE set_val(p_idx IN VARCHAR2,p_value IN VARCHAR2);
PROCEDURE set_val(p_idx IN VARCHAR2,p_value IN NUMBER);
PROCEDURE set_val(p_idx IN VARCHAR2,p_value IN DATE);
FUNCTION get_val(p_idx IN VARCHAR2) RETURN VARCHAR2 ;
FUNCTION get_val_number(p_idx IN VARCHAR2) RETURN NUMBER;
FUNCTION get_val_date(p_idx IN VARCHAR2) RETURN DATE;
PRAGMA RESTRICT_REFERENCES(get_val,WNDS,WNPS);
PRAGMA RESTRICT_REFERENCES(get_val_number,WNDS,WNPS);
PRAGMA RESTRICT_REFERENCES(get_val_date,WNDS,WNPS);
END pkg_session;
/

CREATE OR REPLACE PACKAGE BODY pkg_session IS
sv_parameters parm_type;
PROCEDURE set_val(p_idx IN VARCHAR2,p_value IN VARCHAR2)
IS
BEGIN
sv_parameters(TRIM(UPPER(p_idx))) := SUBSTR(p_value,1,1000);
RETURN;
END set_val;

PROCEDURE set_val(p_idx IN VARCHAR2,p_value IN NUMBER)
IS
BEGIN
set_val(p_idx,TO_CHAR(p_value));
RETURN;
END set_val;

PROCEDURE set_val(p_idx IN VARCHAR2,p_value IN DATE)
IS
BEGIN
set_val(p_idx,TO_CHAR(p_value,’YYYYMMDDHH24MISS’));
RETURN;
END set_val;

FUNCTION get_val(p_idx IN VARCHAR2) RETURN VARCHAR2
IS
BEGIN
RETURN sv_parameters(TRIM(UPPER(p_idx)));
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END get_val;

FUNCTION get_val_number(p_idx IN VARCHAR2) RETURN NUMBER
IS
BEGIN
RETURN TO_NUMBER(get_val(p_idx));
END get_val_number;

FUNCTION get_val_date(p_idx IN VARCHAR2) RETURN DATE
IS
BEGIN
RETURN TO_DATE(get_val(p_idx),’YYYYMMDDHH24MISS’);
END get_val_date;

END pkg_session;
/

CREATE OR REPLACE VIEW VW_TEST
AS SELECT * FROM t WHERE ROWNUM<=pkg_session.get_val_number('P_ROWNUM');

— 未设参数时没有数据
SELECT * FROM VW_TEST;

— 设置参数:

EXEC pkg_session.set_val('P_ROWNUM',10);

— 以下会返回10行:
SELECT * FROM VW_TEST;

–两个条件 并且当不设置值的时候不启用
CREATE OR REPLACE VIEW VW_TEST2
AS SELECT * FROM t WHERE ROWNUM exec pkg_session.set_val(‘P_NAME’,’UCJMH’);

PL/SQL procedure successfully completed.

SQL> select * from vw_test2;

USERNAME
——————————
UCJMH
这个时候就只会有一行数据了

在给定时间间隔,求间隔内出现的记录数

在itpub里看到一个很有意思的sql

一个表中记录了各个地点的报警开始时间,结束时间。

现在想统计,各个地点报警次数和时长,时长=结束时间-开始时间。

要求,同一个地点,开始时间间隔超过10分钟的,这个地点要在结果中再出现一次,10分钟之内的假如有多条,统计条数和报警时长,时长=10分钟内各条时长之和。

create table T_DEMO
(
id VARCHAR2(32) not null,
place_id VARCHAR2(32),
s_time DATE,
e_time DATE
);

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘1’, ‘1’, to_date(’21-08-2014 01:24:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 01:24:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘2’, ‘1’, to_date(’21-08-2014 01:25:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 01:25:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘3’, ‘1’, to_date(’21-08-2014 01:35:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 01:35:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘4’, ‘1’, to_date(’21-08-2014 01:39:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 01:39:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘5’, ‘1’, to_date(’21-08-2014 02:05:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 02:05:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘6’, ‘1’, to_date(’21-08-2014 02:06:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 02:06:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘7’, ‘1’, to_date(’21-08-2014 02:12:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 02:12:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘8’, ‘1’, to_date(’21-08-2014 02:14:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 02:14:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (‘9’, ‘1’, to_date(’21-08-2014 02:50:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 02:50:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’10’, ‘1’, to_date(’21-08-2014 02:52:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 02:52:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’11’, ‘1’, to_date(’21-08-2014 02:57:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’21-08-2014 02:57:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’12’, ‘1’, to_date(’25-08-2014 09:13:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’25-08-2014 09:13:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’13’, ‘1’, to_date(’25-08-2014 09:18:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’25-08-2014 09:18:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’14’, ‘1’, to_date(’25-08-2014 09:30:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’25-08-2014 09:30:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’15’, ‘1’, to_date(’25-08-2014 09:37:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’25-08-2014 09:37:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’16’, ‘1’, to_date(’25-08-2014 09:47:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’25-08-2014 09:47:01′, ‘dd-mm-yyyy hh24:mi:ss’));

insert into t_demo (ID, PLACE_ID, S_TIME, E_TIME)

values (’17’, ‘2’, to_date(’25-08-2014 10:09:00′, ‘dd-mm-yyyy hh24:mi:ss’), to_date(’25-08-2014 10:09:01′, ‘dd-mm-yyyy hh24:mi:ss’));

WITHt2AS

(SELECT  a.place_id,

a.s_time,

a.e_time,

a.id,

floor((a.s_time – to_date(‘2000-01-01′,’YYYY-MM-DD’)) * 24 * 60 / 10) last_cha

FROM t_demo a)

SELECT

place_id 地点,

SUM(e_time – s_time) * 24 * 60 * 60 “时长:秒”,

min(s_time)  开始时间,

COUNT(*) 次数

FROM t2

GROUP BY place_id, last_cha;

导入导出工具04–Oralce数据库中表数据导出为TXT格式

Oracle数据库中表数据导出为TXT格式

  1. 使用SPOOL命令把结果输出到文本中;
  2. 使用编写的C语言的脚本;
——————————- 使用SPOOL命令把结果输出到文本中 ——————————-
— 1.编写脚本为/tmp/orauldr.sql;
set echo on            — 是否显示执行的命令内容
set feedback off       — 是否显示提示符,即多少条记录打一个点
set heading off        — 是否显示字段的名称
set verify off         — 是否显示替代变量被替代前后的语句
set trimspool off      — 去字段空格
set pagesize 1000      — 页面大小
set linesize 50        — linesize设定尽量根据需要来设定,大了生成的文件也大
define fil= ‘/tmp/exp.txt’
prompt *** Spooling to &fil
spool &fil
select col1 || ‘,’ || username || ‘,’ || ‘,’|| password from tbtest; — 格式自己拼接出来,比较灵活,导入也不容易出错
spool off;
— 2.在SQL*PLUS中执行;
SQL>@ /tmp/orauldr.sql;
——————————- 使用SPOOL命令把结果输出到文本中 ——————————-
——————————- 使用编写的C语言的脚本 ——————————-
第三方使用C语言写的工具蛮多的,可以联系sonne.k.wang@gmailcom交流;
——————————- 使用编写的C语言的脚本 ——————————-

导入导出工具03–可传输表空间

可传输表空间
  1. 用途:
    1. 用于不同平台的数据迁移;
    2. 用于不同版本数据库之间的迁移;
  2. 限制:
    1. 不支持XMLSchema类型的数据;
    2. 只是把表空间上的数据传输到目标,用户的对象(序列,视图,包,过程,触发器)需要手动创建
  3. 实验目标:创建测试表空间TBS_TT1,并传输到目标服务器;
  4. 检查是否满足表空间传输的条件:
    1. 查看可传输表空间支持数据库平台和当前数据库的版本;                                              
    2. 查看要传输的表空间集是否是自包含的:
      1. 如果某个表空间集引用了其他表空间的对象,则这个表空间不是自包含的,否则就是自包含;
      2. 只有自包含的表空间集才可以用传输表空间技术;
      3. 使用dbms_tts.transport_set_check来验证表空间是否是自包含的,要把需要表空间传输的表空间列表都写上,中间用逗号分割;
      4. TRANSPORT_SET_VIOLATIONS表是一个临时表,必须在执行dbms_tts.transport_set_check的session中查看,如果有记录返回,则表示表空间集不是自包含的;
      5. 检查的结果;                                                  
    3. 查看数据库的字符集;                                                                                                             
  5. 在源数据库导出表空间;
    1. 创建目录对象:CREATE DIRECTORY dir_tt AS ‘/u01/tt’;                     
    2. 把对应的表空间设置为只读模式:ALTER TABLESPACE tbs_tt1 READ ONLY;                                
    3. 使用数据泵导出,只是导出表空间的元信息:expdp \’sys/oracle as sysdba\’ directory=dir_tt transport_tablespaces=tbs_tt1 dumpfile=tt_tbs_tt1.dmp logfile=tt.log job_name=’job_tt’;                                                      
  6. 转换数据文件格式:
    1. 如果源数据库和目标数据库所在的平台不同需要进行此步骤,把表空间的数据转化为目标平台格式;
    2. rman提供了此功能,可以在源数据库进行也可以在目标数据库进行:
      1. 在源数据库转换:convert tablespace ts1,ts2… to platform <destination platform> format ‘/path/%U’;
      2. 在目标数据库转换:convert datafile df1,df2… from platform <source platform> format ‘/path/%U’;
  7. 把导出的表空间的元信息和表空间的数据文件传到目标数据库服务器,数据文件放到数据库的目录下,元数据放到目录对象下;
  8. 修改源数据库表空间为读写模式:ALTER TABLESPACE tbs_tt1 READ WRITE;            
  9. 在目标服务器导入表空间:
    1. 创建目录对象:CREATE DIRECTORY dir_tt AS ‘/u01/tt’;                      
    2. 在目标数据库上创建表空间上的用户和并授予权限,否则会报错;                         
    3. 如果之前进行了平台的转换操作的话,此时可能需要使用rman对数据文件进行重命名了;
    4. 如果源数据库和目标数据库的块大小不同的话,需要在目标数据库添加源数据库块的cache_size:ALTER SYSTEM SET db_4k_cache_size = 5M;
    5. 把数据导入到目标数据库中:impdp \’sys/oracle as sysdba\’ directory=dir_tt dumpfile=tt_tbs_tt1.dmp transport_datafiles=’/u01/app/oracle/oradata/ORCL/tbs_tt1.dbf’ logfile= tt.log job_name=’job_tt’;                                  
    6. 修改表空间为读写模式:ALTER TABLESPACE tbs_tt1 READ WRITE;(SELECT tablespace_name, status FROM dba_tablespaces WHERE tablespace_name = ‘TBS_TT1’;)           
    7. 修改用户的默认表空间:ALTER USER u1 DEFAULT TABLESPACE tbs_tt1;(SELECT username, default_tablespace FROM dba_users WHERE username = ‘U1’;)          
  10. 验证数据;
— 测试数据;
— 创建表空间;
CREATE TABLESPACE TBS_TT1 DATAFILE ‘/u01/app/oracle/oradata/ORCL/tbs_tt1.dbf’ SIZE 20M AUTOEXTEND ON EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO;
— 创建用户并授权;
CREATE USER u1 IDENTIFIED BY u1 DEFAULT TABLESPACE tbs_tt1;
GRANT CONNECT, RESOURCE TO u1;
— 创建表,序列,并插入测试数据;
CREATE TABLE u1.t1(ID INTEGER, c_lob CLOB) TABLESPACE tbs_tt1;
CREATE SEQUENCE u1.seq_t1;
INSERT INTO u1.t1(ID, c_lob) VALUES (u1.seq_t1.NEXTVAL, to_clob(‘传输表空间-表1中BLOB字段’));
COMMIT;
— 创建视图;
CREATE VIEW v_t1(ID, NAME) AS SELECT ID, to_char(c_lob) FROM u1.t1;
SELECT * FROM v_t1;
— 创建过程;
CREATE OR REPLACE PROCEDURE pr_t1 AS
BEGIN
NULL;
END;
— 查看可传输表空间支持数据库平台和当前数据库的版本;
SELECT d.NAME, i.host_name, i.version, d.platform_name, endian_format
FROM v$transportable_platform tp, v$database d, v$instance i
WHERE tp.platform_name = d.platform_name AND d.db_unique_name = i.instance_name;
— 查看表空间是否是自包含的;
EXECUTE dbms_tts.transport_set_check(‘TBS_TT1’, TRUE, TRUE);
SELECT * FROM transport_set_violations;
— 查看数据库的字符集;
SELECT max(decode(parameter,’NLS_LANGUAGE’, VALUE, NULL)) || ‘_’ ||
max(decode(parameter,’NLS_TERRITORY’, VALUE, NULL)) || ‘.’ ||
max(decode(parameter,’NLS_CHARACTERSET’, VALUE, NULL)) AS “NLS_LANG”
FROM nls_database_parameters;
— 数据文件平台转换的脚本;
RMAN> run{
allocate channel c1 device type disk connect ‘sys/oracle@orcl_source’;
convert tablespace example,users to platform ‘Linux IA (32-bit)’ Format ‘/backup/dmp/%U’;
release channel c1;}

由于bitmap造成的insert相互阻塞

CREATE TABLE t
(
NAME VARCHAR2(20)
);

CREATE BITMAP INDEX idx_b_name ON t(NAME);

INSERT INTO t VALUES(‘U’);
INSERT INTO t VALUES(‘C’);

select sid from v$mystat where rownum<2;  –198

select addr, sid, type, id1,id2, lmode,request,block from v$lock where sid=198 or sid=200;
1 000007FFBDC55D50 198 AE 100 0 4 0 0
2 000000001E2E9600 198 TM 77149 0 3 0 0
3 000007FFB9CE8488 198 TX 65561 1133 6 0 0
–这个时候登录第二个session
select sid from v$mystat where rownum<2;
200

INSERT INTO t VALUES(‘U’);
select addr, sid, type, id1,id2, lmode,request,block from v$lock where sid=198 or sid=200;

1 000007FFBDC55D50 198 AE 100 0 4 0 0
2 000007FFBDC56588 200 AE 100 0 4 0 0
3 0000000026980C10 198 TM 77149 0 3 0 0
4 000007FFB9CE8488 198 TX 196617 1336 6 0 0

这个时候在SESSION2中
INSERT INTO t VALUES(‘E’);

select addr, sid, type, id1,id2, lmode,request,block from v$lock where sid=198 or sid=200;

1 000007FFBDC55D50 198 AE 100 0 4 0 0
2 000007FFBDC56588 200 AE 100 0 4 0 0
3 000000002697E370 200 TM 77149 0 3 0 0
4 000000002697E370 198 TM 77149 0 3 0 0
5 000007FFB9CC9678 200 TX 65568 1131 6 0 0
6 000007FFB9CE8488 198 TX 196617 1336 6 0 0
SEssion不阻塞

这个时候继续在session2 做插入

INSERT INTO t VALUES(‘U’);
1 000007FFBDC55D50 198 AE 100 0 4 0 0
2 000007FFBDC56588 200 AE 100 0 4 0 0
3 000007FFBDC56658 200 TX 196617 1336 0 4 0
4 0000000026980C10 200 TM 77149 0 3 0 0
5 0000000026980C10 198 TM 77149 0 3 0 0
6 000007FFB9CC9678 200 TX 65568 1131 6 0 0
7 000007FFB9CE8488 198 TX 196617 1336 6 0 1

这个时候Insert发生了阻塞 session2在等seesion1释放资源

在这个时候发生一个insert 阻碍了 INSERT 的操作  造成它的原因就是 BITMAP
SELECT OBJECT_ID FROM User_Objects WHERE object_name=’IDX_B_NAME’ ;   –77150

alter session set events ‘immediate trace name treedump level INDEX_OBJECT_ID’;

alter session set events ‘immediate trace name treedump level 52563’