Oracle wait for a undo record 的解决

当 Oracle 的性能有问题的时候 有个要检查的地方是用dba用户 select * from v$session_wait 可以看到所有等待的事件 然后对着等待原因一条一条的google 其中有几种是可以忽略的 有的确实是会反映出问题 wait for a undo record 这个事件 如果出现了大量 是回滚的任务太多被卡住了 show parameter fast_start_parallel_rollback 看看这个参数 如果不是false 请改成关闭 alter system set fast_start_parallel_rollback=false; 它关闭的是回滚的并行操作 按理说是并行应该没什么问题 但是可能不成熟 多了就是会卡住 调整成串行很快卡住的任务就完成了 不要问我为什么 我也不知道 正在寻找 谁知道了也可以告诉我 具体的这个参数可以google 很容易找到官方说明 另文本文参考了如下这篇 这位作者还模拟了一把 更加敬业 https://blog.csdn.net/dbseeker/article/details/8795143

2014年5月16日 · 1 分钟 · Hyacinthus

ORACLE SEQUENCE 的 CACHE 参数问题

今日上线了个应用 发现测试上每笔一秒的交易生产上要5秒 经过追踪活跃的 session 情况 查到全部阻塞到了获取某个 Sequence 的下个值的时候 查阅了一下资料 发现建立 Sequence 的时候 Cache 这个参数很重要 尤其是在RAC集群环境下 设置了 Cache 以后 Oracle 会先将一定数据的序号取到内存里 大大的减少了锁等待的时间和写日志时间 但是在数据库 down 掉 关掉 或者干脆机器内存满了的时候 那些序号都可能消失掉 于是就发生 id 跳序号的情况 还有即使一切正常没有跳序号 RAC 环境还会有记录id次序和时间次序不一致的情况 但是肯定是不会出现重复序号的 所以其实还有一个 ORDER 参数 可以在 RAC 强制保持次序 当然会有一定代价 Cache 的默认值是20 如果使用频繁的话 建议保持在100以上 具体的数值可以在实际应用的时候测试一下 100的时候写入应该比 NOCACHE 能快很多倍 总之 我要说的是 在 RAC 环境下 如果是比较繁忙的应用 不要打 NOCACHE 的主意 完全无法接受 如果要求序列号连续 那只能在应用级别解决了 别想用数据库的 Sequence 了 对了 在把 Cache 从0调整到100后 我们的一个交易(大概有几十个insert) 从5秒降低到了0.5秒 以上基于 11g R2

2014年5月15日 · 1 分钟 · Hyacinthus

Oracle中使用分区表来归档冷数据

为了保持查询的效率 我们应当将不用的数据放在归档表中 另一种场景是业务只需要当天的数据 但是可能需要在后台查询历史数据以供错误分析等用途 这里演示一下如何使用Oracle的分区交换特性 来将数据归档到分区表 演示时主表是普通表 只存一天数据 每天跑批前将前一天的数据转移到按日分区的归档表 主表是分区表的情况可以自行推演 --使用分区表按日归档数据 --建立正常表 和索引 CREATE TABLE CUST_INFO ( CUST_ID VARCHAR2(30), CUST_NAME VARCHAR2(100), ETL_LOAD_DT DATE ) NOLOGGING COMPRESS; CREATE INDEX CUST_INFO_IDX ON CUST_INFO (CUST_ID); --建立归档用的分区表 和分区索引 计划每天一个分区 --分区索引只为演示更加全面,一般归档表无需索引 CREATE TABLE CUST_INFO_ARC ( CUST_ID VARCHAR2(30), CUST_NAME VARCHAR2(100), ETL_LOAD_DT DATE )PARTITION BY RANGE(ETL_LOAD_DT) (PARTITION CUST_INFO_ARC_INIT VALUES LESS THAN(TO_DATE('20140201','YYYYMMDD')) ) NOLOGGING COMPRESS; CREATE INDEX CUST_INFO_ARC_IDX ON CUST_INFO_ARC (CUST_ID) LOCAL; --在正常表中插入数据 我们要把它归档到分区表中 --所以用作分区的ETL_LOAD_DT只能出现同一天的日期 INSERT INTO CUST_INFO VALUES('1','Tom',TO_DATE('20140202','YYYYMMDD')); COMMIT; --检查数据是否插入 结果为1 SELECT COUNT(*) FROM CUST_INFO; --我们看看分区表的分区 结果只有一个字段 --在HIGH_VALUE字段可以看到分区的区间定义 SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='CUST_INFO_ARC'; --现在我们为了将数据归档,先要为当前日期建立一个分区 --注意我们放2月2日的数据 分区定义为小于2月3日 ALTER TABLE CUST_INFO_ARC ADD PARTITION CUST_INFO_ARC_20140202 VALUES LESS THAN(TO_DATE('20140203','YYYYMMDD')); --再次查看分区状态,现在有两个分区了 SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='CUST_INFO_ARC'; --在做操作前,我们检查两个索引的状态 --它们的状态应该都是VALID 或者USABLE SELECT T.STATUS,T.* FROM USER_INDEXES T WHERE INDEX_NAME='CUST_INFO_IDX'; SELECT T.STATUS,T.* FROM USER_IND_PARTITIONS T WHERE T.INDEX_NAME='CUST_INFO_ARC_IDX'; --重要:我们现在利用分区交换特性,将正常表中的数据交换到新建的分区 --注意日期必须与分区的限定匹配,否则会报错,有兴趣的可以自行尝试 ALTER TABLE CUST_INFO_ARC EXCHANGE PARTITION CUST_INFO_ARC_20140202 WITH TABLE CUST_INFO; --检查一下记录是不是已经被交换了 记录应该在分区表里 SELECT COUNT(*) FROM CUST_INFO; SELECT COUNT(*) FROM CUST_INFO_ARC; --现在我们再次检查两个索引的状态,交换操作并不会维护索引 --所以正常表的索引和被交换的那个分区索引都会失效。 SELECT T.STATUS,T.* FROM USER_INDEXES T WHERE INDEX_NAME='CUST_INFO_IDX'; SELECT T.STATUS,T.* FROM USER_IND_PARTITIONS T WHERE T.INDEX_NAME='CUST_INFO_ARC_IDX'; --交换完成后需要将索引重建一下,重建分区索引需要指定分区。 ALTER INDEX CUST_INFO_IDX REBUILD; ALTER INDEX CUST_INFO_ARC_IDX REBUILD PARTITION CUST_INFO_ARC_20140202; --现在再看一次,索引状态已经正常了。 SELECT T.STATUS,T.* FROM USER_INDEXES T WHERE INDEX_NAME='CUST_INFO_IDX'; SELECT T.STATUS,T.* FROM USER_IND_PARTITIONS T WHERE T.INDEX_NAME='CUST_INFO_ARC_IDX'; --其实做完大量的数据移动后,应该重新收集统计信息 --以便查询优化器更好的工作。请注意这里要输入用户名,自行替换。 BEGIN DBMS_STATS.GATHER_TABLE_STATS('MART','CUST_INFO');END; BEGIN DBMS_STATS.GATHER_TABLE_STATS('MART','CUST_INFO_ARC');END; --归档表可以利用程序按照策略方便的删除更旧的不用的数据。语句如下。 ALTER TABLE CUST_INFO_ARC DROP PARTITION CUST_INFO_ARC_INIT; --看看分区已经只剩下最新的一个了 --另外最后一个分区是无法删除的,可以自己尝试。 SELECT * FROM USER_TAB_PARTITIONS WHERE TABLE_NAME='CUST_INFO_ARC'; --实验到此结束 删掉所有的表 DROP TABLE CUST_INFO; DROP TABLE CUST_INFO_ARC;

2014年4月17日 · 2 分钟 · Hyacinthus

cx_Oracle中传入布尔值到存储过程

cx_Oracle 有个方法 cursor.callproc 它可以接受列表或者字典当作传入参数 但是我碰到了困难 如何都传入不了TRUE和FALSE Google了很久 只有一些人提出这个问题 没有答案 只能曲线救国了 sql="""BEGIN dbms_mview.refresh(:view, 'C' , 'ATOMIC_REFRESH' => FALSE ); end;""" cursor.execute(sql,(view_name,)) 希望谁知道怎么直接传入布尔值的给我留言说一下

2014年4月11日 · 1 分钟 · Hyacinthus

Oracle转义字符

程序员都知道 有特殊字符的地方 就应该有转义字符 今天想查数据库中X_开头的字段有多少个 用这样的语句 select count(*) from user_tab_columns where column_name like ‘X_%’ 可结果当然是不对的 因为下划线代表的是一个字符 这就成了X后面至少还有一个字符的字段个数 于是我在下划线前边正斜杠反斜杠的试验 均没有作用 只好去查文档 原来Oracle的转义字符是自己指定的 这样查就可以了 select count(*) from user_tab_columns where column_name like ‘X/_%’ESCAPE ‘/’ 当然把斜线换成除了下划线和百分号的其他任何字符都可以的

2011年6月21日 · 1 分钟 · Hyacinthus

Oracle 11g中慎用exp和imp

在Oracle 11g中 由于11系列的产品存储机制的改变 表在第一次存储数据时才会分配segment 这就导致用exp命令导出数据库会发现空表基本都没有被导出 在网上看到了很多人出了很多办法 什么插入一条数据再删除 什么修改系统参数 我就觉得很可笑 除非特别特殊的情况 为何非要吊死在这个命令上呢 Oracle在10g的时候便已经提供了两个更加先进的替换命令 叫expdp和impdp 感兴趣的人使用expdp help=y看下帮助 或者在网上搜索下用法 就会发现这一对命令用起来格式和exp以及imp是一样的 只不过更加强大 改进了更多的东西而已 所以普通的数据库导入导出 用这一对命令就可以了 别再用落后的exp和imp了

2011年6月15日 · 1 分钟 · Hyacinthus

Oracle11g的lib32

Oracle 11g在各个平台64位操作系统上的安装 无论服务端还是客户端 都没有lib32包了 可是有的程序却必须要32位的库才能运行 我的解决办法是找一个相同平台上的32位的Oracle11g 将其中ORACLE_HOME的lib文件夹复制出来 改名为lib32放到64位的操作系统下 注意这没有结束 还有进到这lib32的目录里 执行ls -l 看看有两个链接的目标是不存在的 记住它们然后将它们删掉 用”ln -s 源文件 链接名”这个命令重新链接 然后就可用了 注意一定要是Oracle11g的 从Oracle10g复制过来lib32是无效的

2011年4月27日 · 1 分钟 · Hyacinthus

Oracle的spool产生的on.lst

最近在服务器上总发现一个叫on.lst的文件 每次删了很快就又出来 在google上搜索这个文件又搜索不到什么消息 今天才有时间调查了下 原来是有人的shell写的有点小问题 其中调用sqlplus的时候 来了个 spool on; 可是spool 后面只能接文件 如果不加扩展名oracle就会用默认的lst 最后就产生了一个on.lst的文件…… 就是这样 记得spool直接接文件 不用先on一下……

2011年4月12日 · 1 分钟 · Hyacinthus

oracle的long数据类型

做ETL的时候碰到一个LONG类型的字段 作为多年的程序员直接就把它当成长整形了 后来发现报错了…… 仔细一查 发现这个LONG和数字相差好远 不知oracle定义的时候是怎么想的 怪不得现在的版本官方不建议用这个类型了 在网上找了点这个类型的资料 1、LONG 数据类型中存储的是可变长字符串,最大长度限制是2GB。 2、对于超出一定长度的文本,基本只能用LONG类型来存储,数据字典中很多对象的定义就是用LONG来存储的。 3、LONG类型主要用于不需要作字符串搜索的长串数据,如果要进行字符搜索就要用varchar2类型。 4、很多工具,包括SQL*Plus,处理LONG 数据类型都是很困难的。 5、LONG 数据类型的使用中,要受限于磁盘的大小。 能够操作 LONG 的 SQL 语句: 1、Select语句 2、Update语句中的SET语句 3、Insert语句中的VALUES语句 限制: 1、一个表中只能包含一个 LONG 类型的列。 2、不能索引LONG类型列。 3、不能将含有LONG类型列的表作聚簇。 4、不能在SQLPlus中将LONG类型列的数值插入到另一个表格中,如insert into …select。 5、不能在SQLPlus中通过查询其他表的方式来创建LONG类型列,如create table as select。 6、不能对LONG类型列加约束条件(NULL、NOT NULL、DEFAULT除外),如:关键字列(PRIMARY KEY)不能是 LONG 数据类型。 7、LONG类型列不能用在Select的以下子句中:where、group by、order by,以及带有distinct的select语句中。 8、LONG类型列不能用于分布查询。 9、PL/SQL过程块的变量不能定义为LONG类型。 10、LONG类型列不能被SQL函数所改变,如:substr、instr。 以上内容出自这里。

2011年4月1日 · 1 分钟 · Hyacinthus

Oracle删除有数据的用户

oracle在drop有数据的用户的时候 会报错误 ORA-01922: CASCADE must be specified to drop ‘username’. 正如提示的 你只需要输入命令 drop user 用户名 cascade; 就会把这个用户的对象全部一起删除

2011年3月18日 · 1 分钟 · Hyacinthus