由9itemp表空间遭遇ORA-01652错误蔓延开来 zt

本文针对ORA-01652错误提供多种解决方案,包括调整临时表空间参数、重建临时表空间及使用SQL命令清理临时段等方法。
http://www.dbadoc.com/2009/11/9i_temp_ora_1652[@more@]

一套核心的rac生产系统,最近老遭遇ORA-01652无法扩临展时表空间的错误,临时表空间有60G,查看使用率在96%左右.按说这么打的temp表空间不应该存在不够用的情况,怀疑是oracle没有自动回收不再使用的临时表空间,google也没有很好的回收的办法,大概总结了一下有这些办法,并且蔓延开很多东西。

从我的测试来看:alter tablespace temp coalesce; alter tablespace temp default storage(pctincrease 1); alter tablespace temp permenant(不适用于create temporary tablespace 创建的临时表空间); 这些方法对于LMT基本无效。

已知的代价较小的一种办法是:给临时表空间增加一个新的临时文件,然后删掉原来的临时文件:

system@oracle>system@oracle> create temporary tablespace temp1
2 tempfile ‘g:orantdatabasetemp1a.dbf’ size 1M reuse
3 extent management local uniform size 64k
4 /

Tablespace created.

system@oracle> alter tablespace temp1
2 default storage (pctincrease 1)
3 /
alter tablespace temp1
*
ERROR at line 1:
ORA-03217: invalid option for alter of TEMPORARY TABLESPACE

system@oracle> alter tablespace temp1 permanent
2 /
alter tablespace temp1 permanent
*
ERROR at line 1:
ORA-03217: invalid option for alter of TEMPORARY TABLESPACE

system@oracle> alter tablespace temp1
2 add tempfile ‘g:orantdatabasetemp1b.dbf’ size 1M reuse
3 /

Tablespace altered.

system@oracle> alter database tempfile ‘g:orantdatabasetemp1a.dbf’ offline
2 /

Database altered.

system@oracle> alter database tempfile ‘g:orantdatabasetemp1a.dbf’ drop
2 /

Database altered.

1.重启数据库有可能释放临时表空间,可是生产库的重启谈何容易。

2.新建临时表空间替换,这个倒跟回收UNDO表空间相似,不过,核心生产上也需要谨慎操作,相关SQL:

SQL> create temporary tablespace temp2 tempfile ‘/dev/rdbdata_temp02′ size 10000M autoextend off;
SQL> alter database default temporary tablespace temp2;
SQL> drop tablespace temp;

然后操作系统层面物理删除文件。

3.如果数据库是11g的,可以shrink 临时表空间,不能shrink其他表空间,(请注意,10g的新特性是shrink 表,非表空间)。其他版本可以coalesce表空间,先附上9i,10g,11g的修改表空间的语法:

1).11g(R1和R2相同)的语法:
ALTER TABLESPACE tablespace
{ DEFAULT [ table_compression ] storage_clause
| MINIMUM EXTENT size_clause
| RESIZE size_clause
| COALESCE
| SHRINK SPACE [ KEEP size_clause]
| RENAME TO new_tablespace_name
| { BEGIN | END } BACKUP
| datafile_tempfile_clauses
| tablespace_logging_clauses
| tablespace_group_clause
| tablespace_state_clauses
| autoextend_clause
| flashback_mode_clause
| tablespace_retention_clause
} ;
2).10g的语法:
ALTER TABLESPACE tablespace
{ DEFAULT
[ table_compression ] storage_clause
| MINIMUM EXTENT size_clause
| RESIZE size_clause
| COALESCE
| RENAME TO new_tablespace_name
| { BEGIN | END } BACKUP
| datafile_tempfile_clauses
| tablespace_logging_clauses
| tablespace_group_clause
| tablespace_state_clauses
| autoextend_clause
| flashback_mode_clause
| tablespace_retention_clause
} ;
3).9i的语法:
ALTER TABLESPACE tablespace
{ datafile_tempfile_clauses
| DEFAULT [ data_segment_compression ] storage_clause
| MINIMUM EXTENT integer [ K | M ]
| ONLINE
| OFFLINE [ NORMAL | TEMPORARY | IMMEDIATE ]
| { BEGIN | END } BACKUP
| READ { ONLY | WRITE }
| PERMANENT| TEMPORARY
| COALESCE
| logging_clause
| [ NO ] FORCE LOGGING
} ;
官方文档的说法:

COALESCE

For each datafile in the tablespace, this clause combines all contiguous free extents into larger contiguous extents.

SHRINK SPACE Clause

This clause is valid only for temporary tablespaces. It lets you reduce the amount of space the tablespace is taking. In the optional KEEP clause, the size_clause defines the lower bound that a tablespace can be shrunk to. It is the opposite of MAXSIZE for an autoextensible tablespace. If you omit the KEEP clause, then the database will attempt to shrink the tablespace as much as possible as long as other tablespace storage attributes are satisfied.

11g:再次强调
SQL>alter tablespace temp shrink space;
11g,10g,9i,8i
SQL>alter tablespace temp coalesce;
这个也有可能报错:
SQL> alter tablespace temp coalesce;
alter tablespace temp coalesce
*
ERROR at line 1:
ORA-03217: invalid option for alter of TEMPORARY TABLESPACE
貌似这条语句不适用于临时表空间,对于永久表空间有效。这个方法看来无效,不过网上好多这样的文章,这些人都没有经过验证就写出来,简直误人子弟。
4.先找出系统中正在使用排序段的session:
SELECT se.username,sid,serial#,sql_address,machine,program,tablespace,segtype,contents
FROM v$session se,v$sort_usage su
WHERE se.saddr=su.session_addr;
看情况kill掉??
SQL>alter system kill session ’sid,serial#’;(慎用)
5.metalink上给出的一种方法:
修改一下TEMP表空间的storage参数,改为非0参数。让Smon进程观注一下临时段,从而达到清理和TEMP表空间的目的。
SQL>alter tablespace temp storage (pct increase 1);
执行这条语句有可能会遭遇一个错误:
===============
SQL> alter tablespace temp default storage(pctincrease 1);
alter tablespace temp default storage(pctincrease 1)
*
ERROR at line 1:
ORA-03217: invalid option for alter of TEMPORARY TABLESPACE
这个错误是由于临时表空间是本地管理的,
==============
等SMON 自动coalesce之后再将参数改为0,
alter tablespace temp storage (pct increase 0);
===============================================
官方文档关于PCTINCREASE参数的解释:
PCTINCREASE
Specify the percent by which the third and subsequent extents grow over the
preceding extent. The default value is 50, meaning that each subsequent extent is
50% larger than the preceding extent. The minimum value is 0, meaning all extents
after the first are the same size. The maximum value depends on your operating
system.
Oracle rounds the calculated size of each new extent to the nearest multiple of the
data block size.
If you change the value of the PCTINCREASE parameter (that is, if you specify it in
an ALTER statement), then Oracle calculates the size of the next extent using this
new value and the size of the most recently allocated extent.
Suggestion: If you wish to keep all extents the same size, you can
prevent SMON from coalescing extents by setting the value of
PCTINCREASE to 0. In general, Oracle Corporation recommends a
setting of 0 as a way to minimize fragmentation and avoid the
possibility of very large temporary segments during processing.
Restriction on PCTINCREASE You cannot specify PCTINCREASE for rollback
segments. Rollback segments always have a PCTINCREASE value of 0.
======================================================
6. 网上给出诊断事件的一种方法
确定TEMP表空间的ts#
SQL> select ts#, name from sys.ts$ ;TS# NAME
———- ————————————————————
0 SYSTEM
1 UNDOTBS1
2 TEMP
3 INDX
4 TOOLS
5 USERS
6 DKH_DATA
7 DKH_INDX
8 PHS_DATA
9 PHS_INDX
10 rows selected.

执行清理操作
SQL>alter session set events ‘immediate trace name DROP_SEGMENTS level 3′ ;

说明:
temp表空间的TS# 为 2*, So TS#+ 1= 3

*************************metalink上一篇文章ID:19047.1摘在这里*************************
Error:  ORA-1652
Text:   unable to extend temp segment by %s in tablespace %s
------- -----------------------------------------------------------------------
Cause:  Failed to allocate an extent for temp segment in tablespace.
Action: Use ALTER TABLESPACE ADD DATAFILE statement to add one or more
        files to the tablespace indicated or create the object in another
        tablespace.

*** Important: The notes below are for experienced users - See Note:22080.1

Explanation:
        This error is fairly self explanatory - we cannot get enough space for
        a temporary segment. The size reported in the error message is
        the number of contiguous free Oracle blocks that cannot be found
        in the listed tablespace.

  NOTE: A "temp segment" is not necessarily a SORT segment in a
        temporary tablespace.
        It is also used for temporary situations while creating or dropping
        objects like tables and indexes in permanent tablespaces.
        eg: When you perform a CREATE INDEX a TEMP segment is created
            to hold what will be the final permanent index data. This
            TEMP segment is converted to a real INDEX segment in the
            dictionary at the end of the CREATE INDEX operation. It remains
            a temp segment for the duration of the CREATE INDEX operation
            and so failures to extend it report ORA-1652 rather than an
            INDEX related space error.

	A TEMPORARY segment may be from:
                A SORT          Used for a SELECT or for DML/DDL

		CREATE INDEX	The index create performs a SORT in the users
				default TEMP tablespace and ALSO uses a TEMP
				segment to build the final index in the INDEX
				tablespace. Once the index build is complete
				the segment type is changed.

		CREATE PK CONSTRAINT

		ENABLE CONSTRAINT

		CREATE TABLE	New tables start out as TEMPORARY segments.
				Eg: If MINEXTENTS is > 1 or you issue
				    CREATE table as SELECT.

                Accessing a GLOBAL TEMPORARY TABLE
                                When you access a global temporary table
                                a TEMP segment is instantiated to hold the
                                temporary data.

	It is worth making sure the TEMP tablespace PCTINCREASE is 0 and
	that it has a sensible (large) storage clause to prevent fragmentation.
        For TEMPORARY temp tablespaces make sure both INITIAL and NEXT are
        set to large values as extent sizes are taken from the NEXT clause
        and not the INITIAL clause.

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/82387/viewspace-1030254/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/82387/viewspace-1030254/

<think> 我们分析给定的代码行: iTemp = (stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword - (stSynFcn.PhaseSync.unPhaseAShiftFlt.half.hword % 51)) 这段代码存在一些潜在的问题和需要注意的地方。下面我将详细解释。 ### 问题分析 1. **变量名不一致**: - 第一个变量:`stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword` - 第二个变量:`stSynFcn.PhaseSync.unPhaseAShiftFlt.half.hword` 注意:第一个是`stSyncFcn`,第二个是`stSynFcn`(少了一个&#39;c&#39;)。这很可能是拼写错误,导致访问了两个不同的结构体变量。 2. **操作含义**: - 该表达式试图计算:用一个值(来自`stSyncFcn`)减去另一个值(来自`stSynFcn`)对51取模的结果。 - 但是,由于两个变量名不一致,它们可能不是同一个数据。 3. **结构体成员解释**: - 从变量名看,`unPhaseAShiftFlt`可能是一个联合体(union)或结构体(struct),其中包含一个`half`成员,而`half`又包含一个`hword`成员(可能是半字,即16位整数)。 - 注意:`half`和`hword`的命名可能表示这是一个16位的值。 4. **取模运算**: - 对51取模(%51)的结果在0到50之间。 - 这里的目的可能是将`stSynFcn.PhaseSync.unPhaseAShiftFlt.half.hword`调整到51的整数倍附近?但是用另一个变量减去这个余数,可能意图是将第一个变量调整到51的整数倍?但逻辑上并不直接。 ### 可能意图 根据表达式,我们猜测意图可能是: - 将`stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword`调整为一个51的整数倍的值,调整的方法是用该值减去它自身除以51的余数?但是这里却用了另一个变量做取模运算。 但实际上,由于两个变量名不同,这可能是错误的。 ### 修正建议 1. **修正变量名一致**: 如果原本意图是同一个变量,那么第二个变量名应该是`stSyncFcn`(注意拼写)。修正后: ```c iTemp = (stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword - (stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword % 51)); ``` 2. **表达式解释**: 修正后,该表达式的含义是:将`stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword`减去其自身除以51的余数,得到的是不超过原值的最大51的整数倍。例如: - 如果原值为100,则余数为100%51=49,那么iTemp=100-49=51- 如果原值为51,则余数为0,iTemp=51-0=51。 所以,这相当于向下取整到最接近的51的整数倍。 3. **注意数据类型**: - 由于使用了取模运算,要求操作数是整数。如果`hword`是整数类型(如int16_t),则没问题;如果是浮点数,则不能直接取模。 ### 代码示例(修正后) 假设我们修正了变量名,并确保操作数是整数: ```c // 假设结构体定义如下(根据变量名推测): typedef union { struct { int16_t hword; // half word, 16位整数 } half; // 可能有其他成员... } UnPhaseAShiftFlt; typedef struct { UnPhaseAShiftFlt unPhaseAShiftFlt; } PhaseSync; typedef struct { PhaseSync PhaseSync; } StSyncFcn; StSyncFcn stSyncFcn; // 注意变量名一致 // 计算 int16_t iTemp = (stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword - (stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword % 51)); ``` ### 注意事项 1. **边界情况**: - 当原值为负数时,取模运算的结果在C语言中是负数(或非负,取决于编译器实现,但C99标准规定余数与被除数同号)。例如,-10 % 51 = -10,那么iTemp = -10 - (-10) = 0。这可能不是期望的结果(期望可能是-51?)。 - 因此,如果原值可能是负数,需要谨慎处理。通常,我们希望得到向零取整还是负无穷取整? 2. **替代方案**: 如果希望得到向下取整(向负无穷方向)到51的整数倍,对于负数也可以正确处理,可以使用: ```c int16_t value = stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword; int16_t remainder = value % 51; if (remainder < 0) { remainder += 51; // 调整余数为非负 } iTemp = value - remainder; ``` 这样,对于负数,例如value=-10,余数=-10,调整后余数=41(因为-10%51=-10,然后+51变成41),然后iTemp=-10-41=-51,即向下取整。 或者直接使用: ```c iTemp = (value / 51) * 51; // 整数除法是向零取整,所以对于负数不是向下取整 ``` 所以这种方法对于负数是向零取整,不是向下取整。 因此,需要根据需求选择。 3. **溢出问题**: - 由于`hword`是16位整数,范围是-32768到32767。而51的整数倍在32767以内最大为32736(51*642=32742,51*643=32793>32767,所以最大倍数32742)。所以不会溢出。 ### 总结 原始代码中变量名不一致很可能是笔误,修正后表达式的作用是:将16位整数向下取整到最近的51的倍数(非负数情况下)。但要注意负数情况下的行为,根据实际需求调整。 §§相关问题§§: 1. 在C语言中,取模运算(%)对于负数的处理规则是什么? 2. 如何实现一个整数向零取整到指定基数的倍数? 3. 结构体和联合体在内存中的布局有什么不同? 4. 在嵌入式系统中,为什么常用位域(bit-field)或联合体(union)来访问硬件寄存器? </think> ### 表达式分析与修正:整数对齐操作 您提供的表达式是一个典型的**整数对齐操作**,常见于嵌入式系统和硬件寄存器操作中。其主要目的是将一个整数值对齐到指定边界(这里是51的倍数)。下面我将详细解析并修正代码中的问题。 #### 1. 原始表达式分析 ```c iTemp = (stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword - (stSynFcn.PhaseSync.unPhaseAShiftFlt.half.hword % 51)) ``` ##### 问题点: 1. **变量名不一致**: - `stSyncFcn` vs `stSynFcn`(缺少 &#39;c&#39;) - 这极可能是拼写错误,导致访问了不同的内存位置 2. **操作含义**: - 从寄存器值中减去其自身对51取模的结果 - 本质是将数值向下对齐到最近的51的倍数 - 例如:100 - (100 % 51) = 100 - 49 = 51 3. **数据类型推断**: - `unPhaseAShiftFlt`:可能是一个联合体(union) - `half.hword`:通常表示16位半字(short类型) - 操作针对硬件寄存器值(常见于嵌入式开发) #### 2. 修正后的代码 ```c // 假设寄存器结构体定义 typedef union { struct { uint16_t hword; // 16位寄存器值 } half; uint32_t full; // 完整32位访问 } PhaseShiftReg; typedef struct { PhaseShiftReg unPhaseAShiftFlt; } PhaseSyncReg; typedef struct { PhaseSyncReg PhaseSync; } SyncFunction; // 修正后的对齐操作 SyncFunction stSyncFcn; // 确保变量名一致 uint16_t iTemp = stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword; iTemp = iTemp - (iTemp % 51); // 向下对齐到51的倍数 ``` #### 3. 关键解释: 1. **对齐操作的数学原理**: ```c 值 : 100 100 % 51 : 49 // 余数部分 结果 : 100 - 49 = 51 // 最近的较小51倍数 ``` 2. **为何需要对齐**: - 硬件寄存器通常需要特定对齐(如缓存行对齐) - DMA传输要求地址对齐 - 内存池管理中的块对齐 - 本例中的51可能是特定硬件要求的分频系数 3. **变量名修正的重要性**: - 原始代码中`stSyncFcn`和`stSynFcn`访问不同内存 - 这会导致计算使用两个不同的寄存器值 - 结果完全错误且不可预测 4. **嵌入式开发最佳实践**: ```c // 推荐使用类型明确的中间变量 uint16_t reg_value = stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword; uint16_t aligned_value = reg_value - (reg_value % ALIGNMENT); // 或使用位操作优化(当对齐值是2的幂时) #define ALIGN_51(x) ((x) & ~0x32) // 仅当51=0b110011时有效 ``` #### 4. 完整使用示例 ```c #include <stdio.h> #include <stdint.h> // 寄存器结构定义 typedef union { struct { uint16_t hword; } half; uint32_t full; } PhaseShiftReg; typedef struct { PhaseShiftReg unPhaseAShiftFlt; } PhaseSyncReg; typedef struct { PhaseSyncReg PhaseSync; } SyncFunction; int main() { SyncFunction stSyncFcn; const uint16_t ALIGNMENT = 51; // 模拟寄存器写入值 stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword = 100; // 对齐操作 uint16_t original = stSyncFcn.PhaseSync.unPhaseAShiftFlt.half.hword; uint16_t aligned = original - (original % ALIGNMENT); printf("原始值: %u, 对齐值: %u\n", original, aligned); // 测试多个值 uint16_t test_values[] = {0, 50, 51, 100, 200}; for (int i = 0; i < 5; i++) { uint16_t val = test_values[i]; uint16_t res = val - (val % ALIGNMENT); printf("%3u -> %3u (偏移: %2d)\n", val, res, val % ALIGNMENT); } return 0; } ``` #### 5. 输出结果分析: ``` 原始值: 100, 对齐值: 51 0 -> 0 (偏移: 0) 50 -> 0 (偏移: 50) // 注意:50%51=50,50-50=0 51 -> 51 (偏移: 0) 100 -> 51 (偏移: 49) // 100-49=51 200 -> 153 (偏移: 47) // 200-47=153 (51*3) ``` #### 6. 特殊边界情况处理: 当值小于对齐基数时: ```c // 原始值50: 50 - (50%51=50) = 0 // 如需保持最小值,可添加判断: uint16_t align_to_51(uint16_t value) { if (value < 51) return 0; // 或保持原值? return value - (value % 51); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值