永平 的个人资料ERN空间照片日志列表更多 ![]() | 帮助 |
|
|
2月12日 Oracle11.1.0.7补丁包地址 ftp://updates.oracle.com/6890831/p6890831_111070_Linux-x86.zip ftp://updates.oracle.com/6890831/p6890831_111070_Linux-x86-64.zip ftp://updates.oracle.com/6890831/p6890831_111070_MSWIN-x86.zip ftp://updates.oracle.com/6890831/p6890831_111070_Win32.zip 当然,需要Metalink帐号密码,可以使用FlashGet之类的软件下载,多线程,比直接从Metalink(通过HTTPS的方式)快多了。 8月18日 RedHat Enterprise Linux 5(RHEL5)安装Oracle 11.1.0.6(11gR1)简要 新鲜出炉的Oracle 11.1.0.6的文档中对以下Linux发行版提供了 Asianux 2.0 Asianux 3.0 Oracle Enterprise Linux 4.0 Oracle Enterprise Linux 5.0 Red Hat Enterprise Linux 4.0 Red Hat Enterprise Linux 5.0 SUSE Enterprise Linux 10.0 估计现在用得最多就是RHEL4和5了。关于在RHEL5上安装Oracle11g,在ITPUB和fenng的Blog上已经有所说明,前者有具体截图,后者有简洁说明。我还是简单写个流程吧: 一、安装RHEL5的时候要注意对硬盘空间的规划,根据Oracle的推荐,Oracle11g要求1G内存(如果达不到那就调小各种参数,反正自己测试用,问题也不大),对应的swap就需要1.5G(如果小于512MB,那么swap=2*RAM,如果大于2G,那么swap=RAM,如果大于8G,那么swap=0.75*RAM,512-2G之间的,1.5*RAM就OK了),/tmp需要400MB,安装企业版的Oracle需要3.47GB,默认库又需要1.6GB。可以用grep MemTotal /proc/meminfo检查。如下可以临时转移/tmp到有空闲资源的地方: su - root mkdir /<AnotherFilesystem>/tmp chown root.root /<AnotherFilesystem>/tmp chmod 1777 /<AnotherFilesystem>/tmp export TEMP=/<AnotherFilesystem> # used by Oracle export TMPDIR=/<AnotherFilesystem> # used by Linux programs like the linker "ld" 结束后恢复: su - root rmdir /<AnotherFilesystem>/tmp unset TEMP unset TMPDIR 二、在正常安装完成RHEL5之后,首先建议停掉SELinux和防火墙,然后检查如下的包是否装全了(rpm -qa | grep 包名) binutils-2.17.50.0.6-2.el5 compat-libstdc++-33-3.2.3-61 elfutils-libelf-0.125-3.el5 elfutils-libelf-devel-0.125 glibc-2.5-12 glibc-common-2.5-12 glibc-devel-2.5-12 gcc-4.1.1-52 gcc-c++-4.1.1-52 libaio-0.3.106 libaio-devel-0.3.106 libgcc-4.1.1-52 libstdc++-4.1.1 libstdc++-devel-4.1.1-52.e15 make-3.81-1.1 sysstat-7.0.0 unixODBC-2.2.11 unixODBC-devel-2.2.11 三、增加用户: su - root groupadd dba groupadd oinstall useradd -c "Oracle Owner" -g oinstall -G dba oracle passwd oracle 之后安装路径的路径,比如: su - root mkdir -p /u01/app/oracle chown -R oracle.oinstall /u01/app chmod -R 775 /u01/app 四、对各类参数,fenng提供了一个简洁的说明,修改 /etc/sysctl.conf,追加如下内容: # First line:SEMMSL SEMMNS SEMOPM SEMMNI kernel.sem=1055 32000 100 128 kernel.shmmax=2147483648 kernel.shmall = 2097152 net.ipv4.tcp_sack = 0 net.ipv4.tcp_timestamps = 0 net.ipv4.conf.default.rp_filter = 0 net.core.optmem_max = 65535 net.core.rmem_default = 4194304 net.core.wmem_default = 262144 net.core.rmem_max = 4194304 net.core.wmem_max = 262144 fs.file-max = 6553600 net.ipv4.ip_local_port_range = 1024 65000 上述值中fs.file-max一项,Oracle的建议是512 * PROCESSES。 然后执行/sbin/sysctl -p激活(root用户)。 五、修改Shell限制。 在/etc/security/limits.conf中增加: oracle soft nproc 2047 oracle hard nproc 16384 oracle soft nofile 1024 oracle hard nofile 65536 在/etc/pam.d/login增加或创建: session required /lib/security/pam_limits.so //对64位系统这条不需要 session required pam_limits.so 对Bourne、Bash或Korn shell,编辑/etc/profile增加: if [ $USER = "oracle" ]; then if [ $SHELL = "/bin/ksh" ]; then ulimit -p 16384 ulimit -n 65536 else ulimit -u 16384 -n 65536 fi fi 对C shell,编辑/etc/csh.login增加: if ( $USER == "oracle" ) then limit maxproc 16384 limit descriptors 65536 endif 六、修改环境变量。选择好你的安装目录后,直接编辑上面提到的shell环境文件,增加类似如下,就可以了: export ORACLE_BASE=/u01/app/oracle //安装路径 export ORACLE_SID=orcl11 export DISPLAY=你的IP:0.0(如果是在本地安装,不要加IP,直接DISPLAY=:0.0就可以了) 完成安装以后还要加上: export ORACLE_HOME=$ORACLE_BASE/product/11.1.0/db_1 //HOME路径 export PATH=$PATH:$ORACLE_HOME/bin export LD_LIBRARY_PATH=$ORACLE_HOME/lib 七、执行./runInstaller,大功告成。 8月15日 Oracle11g for Linux发布两天前在OTN看到了Oracle11g for Linux的下载,今天OTN的主页上也终于更新了。新版本想必已经经过了不少测试和升级,版本号都是11.1.0.6。根据这两天的经验,建议大家白天下载,晚上似乎反而要慢不少,白天估计有5-6个小时就可以了(用FlashGet)。 6月20日 分组连接列字符串新法 西藏游记看来还需要时间慢慢整理,先来共享一个Oracle技巧吧。在以前一篇blog里我写过自定义聚集函数——一条语句将多行的列中字符串连接起来,技术总是在进步的。在这一期的Oracle Magazine中的AskTom,学到了一个不错的方法。从8i开始Oracle增加了分析函数,从9iR1开始,又有了SYS_CONNECT_BY_PATH函数,于是,产生了下面一个更加简单的方法。 [code] CREATE TABLE test AS SELECT rownum office, chr(ascii('a') + rownum - 1) staff FROM all_objects WHERE rownum < 10; INSERT INTO test SELECT rownum, chr(ascii('o') + rownum - 1) FROM all_objects WHERE rownum < 10; SELECT * FROM test; 1 a 2 b 3 c 4 d 5 e 6 f 7 g 8 h 9 i 1 o 2 p 3 q 4 r 5 s 6 t 7 u 8 v 9 w SELECT office, ltrim(MAX(sys_connect_by_path(staff, ',')), ',') namelist FROM (SELECT office, staff, row_number() over(PARTITION BY office ORDER BY staff) rn FROM test) v START WITH rn = 1 CONNECT BY PRIOR rn = rn - 1 AND PRIOR office = office GROUP BY office ORDER BY office; 1 a,o 2 b,p 3 c,q 4 d,r 5 e,s 6 f,t 7 g,u 8 h,v 9 i,w [/code] 其实原理并不复杂,就是通过ROW_NUMBER()函数实现分组编号,然后根据编号递增来分组连接,将SYS_CONNECT_BY_PATH函数第二个参数以及外面的LTRIM参数替换成你需要的符号就可以了。不过注意两点哦,一个,这个方法只有在Oracle9iR1之后才能用;第二,如果你想用空('')连接,那不能直接在SYS_CONNECT_BY_PATH里用空('')作为参数,而要用其他字符然后在外面用REPLACE替换,否则就可能遇到ORA-30003错误,即SYS_CONNECT_BY_PATH的参数非法。 有了这个法子,原来那个复杂的方法基本可以抛弃咯^_^ 4月6日 ORA-04030的一种原因 4030的错误往往也挺吓人的,一看就涉及内存问题啊。今天在一个内部使用的数据库上遇到了。往往4030的解决方法都是增加PGA,或者反之,减少SORT_AREA_SIZE/HASH_AREA_SIZE。根本原因其实就是当Oracle试图向OS申请会话内存(session memory)时,OS返回错误,一般是内存不足之类。所以上来就提高PGA_AGGREGATE_TARGET也是不合适的。今天就是这个情况。 在客户端跑一个稍微复杂点的查询时候,出现了ORA-04030,其它同事也反映这个情况出现几天了,即便程序可以运行也慢得像头牛。今天我是忍无可忍了,决心花点时间了解一下。连上服务器,alert.log里果然不少报错。show parameter pga一看,600M,作为这个数据库倒也挺合适。再查询V$PGASTAT,真正花费的内存空间都是150M左右,并不大啊。仔细查查V$SESSTAT,只有三四个占内存超过10M的会话,实时统计总共也就是120M。看来并不是PGA设置太小。忽然想到这台服务器是Win2000 32bit,配置8G内存,联想到了1.7G的限制。不过当初装机器的同事已经设置了AWE,应该可以用到3G啊。 又是一阵show parameter,终于发现了问题,猜想是对的。DB_BLOCK_BUFFERS设置了307000+,也就是2.4G的DB_CACHE,然后SHARED_POOL_SIZE=100M,这加起来都3.1G,突破限制了,居然还不知道为什么设置了JAVA_POOL_SIZE=100M。赶紧改……于是将DB_CACHE调整到了2G(调低DB_BLOCK_BUFFERS),由于没有Java程序或过程,所以JAVA_POOL_SIZE=0,顺手又将SGA_MAX_SIZE降到2.2G,这样数据库就不会盲目相信参数,突破OS进程限制申请空间了。通知同事重新启动数据库,果然再没出现错误了,查V$PGASTAT果然可以分配更多空间了,一般都稳定在200-300M了,程序运行快了不少。 回过头来说,8G内存的PC服务器,只用Oracle,才能用到3G,还真是浪费。可惜是服务器内存,不然拔一条自己用了,哈哈。没办法,现在申请个硬盘都难,还是别指望变成小型机或者升64位了。 4月3日 9i的ORA-22856 今天同事为分区表加一个字段,死活报Ora-22856,这个错误原本是提示无法为含有对象类型的表增加列,而我也记得曾经正常为分区表增加过字段啊。上网一搜,原来是9i的一个bug,到Metalink上找到了资料:
This note gives a brief overview of bug 2421054. Affects:
Fixed:
Symptoms:
Related To:
DescriptionThis is an enhancement to allow "ALTER TABLE" to ADD/DROP 晕,仔细一看那张分区表,确实分区都是COMPRESS的,这到10g才修复,汗。看来是9i实现表压缩的基础算法造成的了。顺手在Metalink上又发现一个相关的Bug:
This note gives a brief overview of bug 3262424. Affects:
Fixed:
Description对我们的应用COMPRESS一下倒确实省地方,不过这几个bug一关联,还真是麻烦啊,只能设计好再动手了。ALTER TABLE NOCOMPRESS does not work for compressed partitioned 3月23日 Oracle新闻——10gR2文档更新了MSN宕掉之前就发现了,一直没有报,现在弥补一下。Oracle有时候做事情就是不声不响的,呵呵。OTN主页上曾经发了一个头条Explore the Oracle Database 2 Day + Performance Tuning Guide。进去一看,还在原来文档的页面,但是现在进去下面的版权日期已经改成2007了,篇幅更大了。内容上最大的变化是增加了两篇文档:2 Day + Real Application Clusters Guide和2 Day + Performance Tuning Guide,另外更新若干的文档。我正在看的Administrator's Guide从B14231-01更新到了B14231-02,调优文档好像没有变化,其他就不太清楚了。相比也不是很大的改写,估计就是修正而已。这样也挺好,不像以前我看了几篇9iR2的文档之后才发现原来文档也有errata的。 2月1日 如何真正NOLOGGING从前几天bigboar要做一个大表更新的项目引发的讨论,CTAS还是INSERT产生redo多。后来在fsm启发下又复习了遍Tom的结论。具体内容就不翻译了,转贴一下:
Table Mode Insert Mode ArchiveLog mode result
----------- ------------- ----------------- ---------- LOGGING APPEND ARCHIVE LOG redo generated NOLOGGING APPEND ARCHIVE LOG no redo LOGGING no append "" redo generated NOLOGGING no append "" redo generated LOGGING APPEND noarchive log mode no redo NOLOGGING APPEND noarchive log mode no redo LOGGING no append noarchive log mode redo generated NOLOGGING no append noarchive log mode redo generated 简单来讲,就是表的模式和归档模式具有优先决定权,当表本身NOLOGGING时,指定了APPEND的hint才不产生redo(direct模式的sqlldr应该是一样的),另外就是非归档下则无论表状态只要APPEND总会生效。
其实也就是一个规律,具体的测试就不做了。呵呵。 BTW:在后来的讨论中其实还涉及到UNDO,CTAS产生UNDO方面还是有优势的,INSERT毕竟要记录rowid作为UNDO信息,而CTAS是DDL,立即提交,应该只是在涉及修改数据字典的地方产生UNDO而已。所以Tom在他的帖子里也是推荐用CTAS代替大量UPDATE。当然啦,CTAS也是有弱点的,毕竟表结构不能自定义,这样如果原表设计并不合理的时候就无法顺便改表结构了。
CTAS+PARALLEL(如果可以并行的话)是目前我能想到的最快速度了。 9月20日 升级后未更新数据字典等导致的ORA-904 昨晚同事迁移一个数据库,今早过来居然发现TRUNCATE一个表的时候报“ORA-904 DROP_SEGMENTS: 非法的标识符”,记得平时904是非法列名(invalid column name)的,怎么变成这个了?而且TRUNCATE的时候报错。看起来DROP_SEGMENTS是某个数据字典里的列。后来就更怪异了,有的表可以,有的表不可以。但是DELETE是没问题的。 到metalink上一搜索,倒是很容易发现了问题。 [quote]
The information in this article applies to:Oracle Server - Enterprise Edition - Version: 9.2.0.5This problem can occur on any platform. ErrorsORA-904 %s: invalid identifier / invalid column nameSymptomsORA-00904: "DROP_SEGMENTS": invalid identifier repeatedly in alert.log after application of 9.2.0.5 PatchsetWhenever "drop table " or "truncate table" is issued,this error is seen CauseThe post installation scripts were not run properly,so drop_segments column is missing fromsys.mon_mods$ . One or more of these post installation scripts would add the new column to the database and if the script is not run properly, it will cause an ORA-904 in the application later on. FixConnect to the SQL session as SYS and issue the following:SQL> desc sys.mon_mods$ If the drop_segments is missing then we are getting ORA-904.If this is the case,we can do one of these: 1.Shutdown the database- startup migrate and then run catpatch.sql and catalog.sql(the scripts that are needed to be run as a post-installarion process). 2.Add the drop_segments column using: SQL> alter table sys.mon_mods$ add ( drop_segments number default 0 ); Then run $ORACLE_HOME/rdbms/admin/catalog.sql again. [/quote] 呵呵,一问同事,果然是在迁移前为新的服务器打了9208的补丁,但是没有执行catalog.sql和cataproc.sql。汗……目前倒是不影响运行,等晚上执行脚本咯。 6月8日 Pro*C实现导出Oracle表为文本文件近日工作需要,要大批量导出数据,开始用SQL*Plus的SPOOL功能。结果老是提示“xrealloc: cannot reallocate XXX bytes”。而且每次发生的时间还不同,有时候是到文件1G就出错,有时候是2G多出错。怀疑是32位Linux问题,换到Solaris 8上还是如故。客户端都是9201的,到Metalink上搜索没有结果。郁闷之余到Oracle-l上发了个邮件,收到一位高手的指点,说可能是内存泄露问题,SQL*Plus的开发人员估计也不会想到有人会导出如此大量数据。在邮件往复之间,那位高手提醒可以用UTL_FILE来导出。忽然想起Tom的两本书里都有提到用PL/SQL来导出,于是翻出书里的那个网址http://asktom.oracle.com/~tkyte/flat/index.html,进去一看,PL/SQL的效率比SQL*Plus要高,缺点是生成的文件必须在主机上。SQL*Plus可以调整arraysize来提高效率(当然经我实践大数据量时还有内存泄露之虞)。Pro*C是高效的方法,缺点是需要写程序、编译。 硬着头皮看Pro*C咯,好在Tom给了原始代码,抓下来放到一台Linux的机器上proc报错,应该是proc配置include库的问题,找到一个makefile,倒是没啥问题了,但是最后链接失败,报无法识别'sqlca'。到网上一搜,和我一样晕的人还有,要修改代码,多include进<SQLCA.H>,但是看Tom的帖子似乎没提到这个问题,不知道为什么。 下面是修改后的源代码,我顺便在里面修改了会话的一些参数,以处理中文和时间格式: [code] #include <stdio.h> #include <string.h> #include <ctype.h> #include <SQLCA.H> #define MAX_VNAME_LEN 30 #define MAX_INAME_LEN 30 static char * USERID = NULL; static char * SQLSTMT = NULL; static char * ARRAY_SIZE = "10"; #define vstrcpy( a, b ) \ (strcpy( a.arr, b ), a.len = strlen( a.arr ), a.arr) EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE sqlda; extern SQLDA *sqlald(); extern void sqlclu(); static void die( char * msg ) { fprintf( stderr, "%s\n", msg ); exit(1); } /* this array contains a default mapping I am using to constrain the lengths of returned columns. It is mapping, for example, the Oracle NUMBER type (type code = 2) to be 45 characters long in a string. */ static int lengths[] = { -1, 0, 45, 0, 0, 0, 0, 0, 2000, 0, 0, 18, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 512, 2000 }; static void process_parms( argc, argv ) int argc; char * argv[]; { int i; for( i = 1; i < argc; i++ ) { if ( !strncmp( argv[i], "userid=", 7 ) ) USERID = argv[i]+7; else if ( !strncmp( argv[i], "sqlstmt=", 8 ) ) SQLSTMT = argv[i]+8; else if ( !strncmp( argv[i], "arraysize=", 10 ) ) ARRAY_SIZE = argv[i]+10; else { fprintf( stderr, "usage: %s %s %s\n", argv[0], "userid=xxx/xxx sqlstmt=query ", "arraysize=<NN>\n" ); exit(1); } } if ( USERID == NULL || SQLSTMT == NULL ) { fprintf( stderr, "usage: %s %s %s\n", argv[0], "userid=xxx/xxx sqlstmt=query ", "arraysize=<NN>\n" ); exit(1); } } static void sqlerror_hard() { EXEC SQL WHENEVER SQLERROR CONTINUE; fprintf(stderr,"\nORACLE error detected:"); fprintf(stderr,"\n% .70s \n", sqlca.sqlerrm.sqlerrmc); EXEC SQL ROLLBACK WORK RELEASE; exit(1); } static SQLDA * process_1(char * sqlstmt, int array_size ) { SQLDA * select_dp; int i; int j; int null_ok; int precision; int scale; int size = 10; fprintf( stderr, "Unloading '%s'\n", sqlstmt ); fprintf( stderr, "Array size = %d\n", array_size ); EXEC SQL WHENEVER SQLERROR DO sqlerror_hard(); EXEC SQL PREPARE S FROM :sqlstmt; EXEC SQL DECLARE C CURSOR FOR S; if ((select_dp = sqlald(size,MAX_VNAME_LEN,MAX_INAME_LEN)) == NULL ) die( "Cannot allocate memory for select descriptor." ); select_dp->N = size; EXEC SQL DESCRIBE SELECT LIST FOR S INTO select_dp; if ( !select_dp->F ) return NULL; if (select_dp->F < 0) { size = -select_dp->F; sqlclu( select_dp ); if ((select_dp = sqlald (size, MAX_VNAME_LEN, MAX_INAME_LEN)) == NULL ) die( "Cannot allocate memory for descriptor." ); EXEC SQL DESCRIBE SELECT LIST FOR S INTO select_dp; } select_dp->N = select_dp->F; for (i = 0; i < select_dp->N; i++) select_dp->I[i] = (short *) malloc(sizeof(short) * array_size ); for (i = 0; i < select_dp->F; i++) { sqlnul (&(select_dp->T[i]), &(select_dp->T[i]), &null_ok); if ( select_dp->T[i] < sizeof(lengths)/sizeof(lengths[0]) ) { if ( lengths[select_dp->T[i]] ) select_dp->L[i] = lengths[select_dp->T[i]]; else select_dp->L[i] += 5; } else select_dp->L[i] += 5; select_dp->T[i] = 5; select_dp->V[i] = (char *)malloc( select_dp->L[i] * array_size ); for( j = MAX_VNAME_LEN-1; j > 0 && select_dp->S[i][j] == ' '; j--); fprintf (stderr, "%s%.*s", i?",":"", j+1, select_dp->S[i]); } fprintf( stderr, "\n" ); EXEC SQL OPEN C; return select_dp; } static void process_2( SQLDA * select_dp, int array_size ) { int last_fetch_count; int row_count = 0; short ind_value; char * char_ptr; int i, j; for ( last_fetch_count = 0; ; last_fetch_count = sqlca.sqlerrd[2] ) { EXEC SQL FOR :array_size FETCH C USING DESCRIPTOR select_dp; for( j=0; j < sqlca.sqlerrd[2]-last_fetch_count; j++ ) { for (i = 0; i < select_dp->F; i++) { ind_value = *(select_dp->I[i]+j); char_ptr = select_dp->V[i] + (j*select_dp->L[i]); printf( "%s%s", i?",":"", ind_value?"(null)":char_ptr ); } row_count++; printf( "\n" ); } if ( sqlca.sqlcode > 0 ) break; } sqlclu(select_dp); EXEC SQL CLOSE C; EXEC SQL COMMIT WORK; fprintf( stderr, "%d rows extracted\n", row_count ); } main( argc, argv ) int argc; char * argv[]; { EXEC SQL BEGIN DECLARE SECTION; VARCHAR oracleid[50]; EXEC SQL END DECLARE SECTION; SQLDA * select_dp; process_parms( argc, argv ); /* Connect to ORACLE. */ vstrcpy( oracleid, USERID ); EXEC SQL WHENEVER SQLERROR DO sqlerror_hard(); EXEC SQL CONNECT :oracleid; fprintf(stderr, "\nConnected to ORACLE as user: %s\n\n", oracleid.arr); EXEC SQL ALTER SESSION SET NLS_DATE_FORMAT = 'YYYYMMDDHH24:MI:SS'; EXEC SQL ALTER SESSION SET NLS_LANGUAGE = "SIMPLIFIED CHINESE"; select_dp = process_1( SQLSTMT, atoi(ARRAY_SIZE) ); process_2( select_dp , atoi(ARRAY_SIZE)); /* Disconnect from ORACLE. */ EXEC SQL COMMIT WORK RELEASE; exit(0); } [/code] 顺便附上我的makefile,在RHEL AS3上用的: [code] CC=gcc LD=ld OBJ=obj/ ##########数据库编译选项########### PROCFLAGS=unsafe_null=yes dynamic=ansi mode=oracle dbms=V8 parse=full\ release_cursor=no sqlcheck=SEMANTICS ireclen=512 include=./.\ sys_include=/usr/include sys_include=/usr/lib/gcc-lib/i386-redhat-linux/3.2.3/include \ def_sqlcode=yes INCL=-I/usr/include -I./. -I${ORACLE_HOME}/precomp/public BIN_LIBS= -lc -L${ORACLE_HOME}/lib -lclntsh ##########编译规则################ .SUFFIXES: .pc .o .c .c.o: ${CC} -g -c $*.c ${INCL} .pc.o: proc $(PROCFLAGS) iname=$*.pc $(CC) -g -c $*.c ${INCL} rm -f $*.c $*.lis all:unload unload:unload.o rm -f $@ ${CC} -o $@ unload.o \ $(BIN_LIBS) ######################################################### #编译公用目标文件 ######################################################### ########清理目标文件########################### clean: rm -f *.o *.lis [/code] 编译以后生成unload程序,执行如下: unload userid=XXX/XXX sqlstmt='select * from dual' arraysize=100>XXX.DAT 这样DAT文件里就是数据了。 经我测试,在数据库主机上,30分钟导出了7GB的文件,强啊!效率上可以调整的一个是arraysize参数,这个一般100-200都可以,更大的除非你IO超强,不然也没有意义;另一个是所谓并行,其实这个C程序也就是执行SELECT语句,因此将原表改为PARALLEL就可以充分利用系统资源了^_^。 5月28日 有趣的IT人发现了两个很有意思的网站,一个是读Oracle Wait Interface的时候看到的,反RAID-5的联盟(实际上还反对其他RAID目标),www.baarf.com。想想,因为RedoLog放在RAID-5上确实还和领导反映过几次,但是没人听,没想到老外们已经行动起来了,呵呵。稍微看了一下参加者名单,不乏牛人啊。 另一个有意思的网站是http://www.viksoe.dk/code/asmil.htm,一个研究用386汇编写ASP.NET页面的家伙做的东西,还附上了一个编译器,没有测试,有兴趣的可以下载试试。 4月11日 ORACLE一个SELECT会同时使用两个单独的索引吗?SQL> create table test1 as select * from all_objects; 表已创建。 SQL> create index idx_test1_owner on test1(owner); 索引已创建。 SQL> create index idx_test1_otype on test1(object_type); 索引已创建。 SQL> begin 2 dbms_stats.gather_table_stats(user,'test1',cascade=>true); 3 end; 4 / PL/SQL 过程已成功完成。 SQL> set autot traceonly exp SQL> select * from test1 where owner='YAOYP' and object_type='TABLE'; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=12 Card=28 Bytes=2576) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=12 Card=28 Bytes=2576) 2 1 BITMAP CONVERSION (TO ROWIDS) 3 2 BITMAP AND 4 3 BITMAP CONVERSION (FROM ROWIDS) 5 4 INDEX (RANGE SCAN) OF 'IDX_TEST1_OWNER' (NON-UNIQUE) (Cost=2) 6 3 BITMAP CONVERSION (FROM ROWIDS) 7 6 INDEX (RANGE SCAN) OF 'IDX_TEST1_OTYPE' (NON-UNIQUE) (Cost=4) 这里其实是进行了一个B*树索引到位图索引的转换,当Oracle使用CBO并判断到组合两个索引会更合算时,会将B*树索引中的rowid转换为位图进行关联——位图索引的关联更快,然后按照关联出的rowid取得信息。 4月8日 Oracle新闻——Cost Based Oracle Fundamentals电子书发布名书就不多介绍了,可以到http://www.apress.com/book/bookDisplay.html?bID=10081查看介绍和勘误等。作者是鼎鼎大名的Jonathan Lewis。建议大家去买本儿,不会后悔的。不过还是提供一个电子书的下载途径吧^_^ 4月2日 索引空间是可以重用的刚开始学Oracle的时候确实在网上看到过这么一个myth,索引只会扩展得越来越大,特别是经常delete,除掉插入相同的索引值,空间不会释放出来。后来在AskTom的站上看到关于重建索引是否必要的帖子时,看到了一个试验。今天看Expert Oracle Database Architecture时候,顺手试验了一下: 先建张简单的表。 SQL> create table test (id number,constraints pk_test primary key(id)); 表已创建。 SQL> insert into test values(1); 已创建 1 行。 SQL> insert into test values(2); 已创建 1 行。 SQL> insert into test values(999999999); 已创建 1 行。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 3 1 0 8000 43 那么看看真的是只有相同的索引值才能重用空间。 SQL> begin 2 for i in 2 .. 99999 3 loop 4 delete from test where id = i; 5 commit; 6 insert into test values (i + 1); 7 commit; 8 end loop; 9 end; 10 / PL/SQL 过程已成功完成。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 3 1 0 8000 43 显然,没有出现索引的疯狂增长。 SQL> select * from test; ID ---------- 1 100000 999999999 一条删除一条插入不过瘾,那看看批量的呢? SQL> insert into test 2 select rownum+1 from all_objects where rownum<100000; 已创建49797行。 SQL> commit; 提交完成。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 49800 180 1 1448032 738313 SQL> delete from test where id between 2 and 100000-1; 已删除49797行。 SQL> commit; 提交完成。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 49800 180 1 1448032 738313 这里索引增长了,并没有回缩,但其实是有空块的,目标不是在块管理,所以没有用DBMS_SPACE.SPACE_USAGE(表空间是ASSM)检查块的情况。 SQL> insert into test 2 select rownum+1 from all_objects where rownum<100000; 已创建49797行。 SQL> commit; 提交完成。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 49800 180 1 1448032 738313 哈哈,还是重用了空间的。下面的测试说明如果插入的索引值都不是在删除产生的“空洞”中,效果是一样的。 SQL> truncate table test; 表被截断。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 0 1 0 8000 SQL> insert into test values(1); 已创建 1 行。 SQL> commit; 提交完成。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 1 1 0 8000 13 SQL> begin 2 for i in 1 .. 999999 3 loop 4 delete from test where id = i; 5 commit; 6 insert into test values (i + 1); 7 commit; 8 end loop; 9 end; 10 / PL/SQL 过程已成功完成。 SQL> analyze index pk_test validate structure; 索引已分析 SQL> select lf_rows,lf_blks,br_blks,btree_space,used_space from index_stats; LF_ROWS LF_BLKS BR_BLKS BTREE_SPACE USED_SPACE ---------- ---------- ---------- ----------- ---------- 1 1 0 8000 13 3月9日 Partition Exchange可以不检查分区条件么?昨天看到CNOUG的调优版上有网友问分区的问题:分区表可以在现有的表中创建吗?fly115提到了可以交换分区,可那位朋友说的是已经有大量的数据了,可以不管分区条件直接交换到分区里么?fly115提供了一个不错的子句: ALTER TABLE table_name EXCHANGE PARTITION part_name WITH TABLE table2_name INCLUDING INDEXES WITHOUT VALIDATION; 这招确实挺强,可是这样的话Oracle怎么做Partition Pruning呢?试验一下。 SQL> create table t_heap 2 (object_id number(22), 3 object_name varchar2(30)); 表已创建。 SQL> insert into t_heap 2 select object_id, object_name from all_objects; 已创建34362行。 SQL> commit; 提交完成。 SQL> create index idx_t_heap 2 on t_heap(object_id); 索引已创建。 SQL> select * from t_heap 2 where object_id = 90146; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 90146 CUSTSERVINFO_0201 SQL> create table t_part 2 (object_id number(22), 3 object_name varchar2(30)) 4 partition by range(object_id) 5 (partition part1 values less than (90000), 6 partition part2 values less than (maxvalue)); 表已创建。 SQL> create index idx_t_part 2 on t_part(object_id) local; 索引已创建。 SQL> alter table t_part exchange partition part1 with table t_heap including indexes; alter table t_part exchange partition part1 with table t_heap including indexes * ERROR 位于第 1 行: ORA-14099: 未对指定分区限定表中的所有行 SQL> alter table t_part exchange partition part1 with table t_heap including indexes without validation; 表已更改。 SQL> select * from t_part 2 where object_id > 90000; 未选定行 SQL> exec DBMS_STATS.GATHER_TABLE_STATS(OwnName => 'YAOYP',TabName => 'T_PART',Estimate_Percent => SYS.DBMS_STATS.AUTO_SAMPLE_SIZE,Method_Opt => 'FOR ALL INDEXED COLUMNS SIZE AUTO',Cascade => TRUE); PL/SQL 过程已成功完成。 SQL> select * from t_part 2 where object_id > 90000; 未选定行 SQL> select * from t_part partition (part1) 2 where object_id = 90146; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 90146 CUSTSERVINFO_0201 SQL> spool off 显然在指定了扫描某个分区后才能显示正确的结果,否则由于Oracle根据分区条件已经排除了真正拥有数据的part1,结果不能显示出来了。中间我还用DBMS_STATS分析了表和索引列,也并没有什么效果。看来,在确信符合分区条件的时候,是可以偷个懒——节约不少检查分区条件的时间,其实也就是全表搜索是否有超过分区条件的行;否则这样“野蛮施工”会造成结果异常哦。 3月2日 Oracle新闻——发布了补丁包10.2.0.2今天才看到的,所以也当是新闻吧,在metalink上可以下载了。另外也可以用metalink帐号到FTP站点下载,还可以用FlashGet下,可惜我白天是通过代理,即便是FlashGet,也不能多线程。和往常一样,这样的版本大多是修正Bug。 说到Bug,今天用Windows 2003 Enterprise Server居然也遇上了蓝屏,Oracle比Windows当然稳定很多,虽说出个600后Crash的情况也遇到一些,但是就加在上面的负载和无差错运行时间来说,还是不错的。但是今天就看到一个Oracle自己把自己玩死的例子。9201上Merge作为一个新引入的指令,有个大Bug,搜索metalink的时候发现Oracle系列产品全部有这个问题:使用Merge时插入语句存在问题,可能违反主键约束或多插入一条重复记录。于是ERP、Portal、OWB等等都能搜索到相同的错误 3月1日 Oracle新闻——Raptor改名了其实应该说是有名字了,从Early Adopter Release 4开始,Raptor改名叫Oracle SQL Developer咯,还是保持免费,也更新到了Early Adopter Release 5。没增加很多新特性,修正了一些问题,增加了对分区表的导出支持等等。 另外2月24日开始提供Oracle Database 10g Express Edition for Windows和Linux x86版本的下载。 Oracle还为其他数据库开发了Grid Control的插件Oracle Enterprise Manager 10g Grid Control Extensions ,没有测试,“看上去很美”,呵呵。 2月22日 终于重新连上了JL Computer Consultancy终于重新连上了JL Computer Consultancy,Jonathan Lewis的主页,其中的The Oracle (tm) User's Co-operative FAQ是很不错的,强烈推荐。我也不知道为什么,从去年年中就开始无法连上了——测试过好多好多次啊差点就想找代理了,还以为他发了什么反华的帖子呢,今天突然就可以了,开心,哈哈。但是非常可惜,Thomas Kyte的Blog还是连不上(估计是对整个blogspot的解析被封了,以前打算用过它的Blog空间,也是因此而作罢),不过有了AskTom的站点,也算知足了吧。 BTW,在CNOUG的AskTom翻译计划又搁置了很久,一定找空闲继续! 2月12日 Oracle新闻——PL/SQL Developer 7推出这个老牌软件又推出了新版,看起来变化还不小,增加了类似PowerDesign的数据结构图、SELECT出的结果转换为图表、一个SQL Windows中同时执行多条语句、比较多表并同步、从ODBC向Oracle中导入数据、在DataGrid显示汇总值、增加一个查询生成器的插件、OFS管理器等多项功能,具体可以查看http://www.allroundautomations.nl/plsqldev7.html并下载试用,另外零售版网上也已经有了。 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|