昨天在做测试的时候发现一个非常奇怪的问题:在程序的查询模块中做查询的时候,开始速度很快,但是过了一段时间以后速度就变慢,最后干脆就报错,不工作了。在排错的过程中,发现Oracle临时表空间暴涨,达到了几十个GB,在Oracle中对Session进行跟踪,发现磁盘空间还在不停的消耗,几乎是每隔5s,临时表空间就会增长500MB左右,最后报错的原因应该是因为没有磁盘空间可以分配造成的。这是一件十分恐怖的事情。
我们知道Oracle临时表空间主要是用来做查询和存放一些缓存的数据的,磁盘消耗的一个主要原因是需要对查询的结果进行排序,如果没有猜错的话,在磁盘空间的(内存)的分配上,Oracle使用的是贪心算法,如果上次磁盘空间消耗达到1GB,那么临时表空间就是1GB,如果还有增长,那么依此类推,临时表空间始终保持在一个最大的上限。像上文提到的恐怖现象经过分析可能是以下几个方面的原因造成的。
1. 没有为临时表空间设置上限,而是允许无限增长。但是如果设置了一个上限,最后可能还是会面临因为空间不够而出错的问题,临时表空间设置太小会影响性能,临时表空间过大同样会影响性能,至于需要设置为多大需要仔细的测试。
2.查询的时候连表查询中使用的表过多造成的。我们知道在连表查询的时候,根据查询的字段和表的个数会生成一个迪斯卡尔积,这个迪斯卡尔积的大小就是一次查询需要的临时空间的大小,如果查询的字段过多和数据过大,那么就会消耗非常大的临时表空间。
3.对查询的某些字段没有建立索引。Oracle中,如果表没有索引,那么会将所有的数据都复制到临时表空间,而如果有索引的话,一般只是将索引的数据复制到临时表空间中。
针对以上的分析,对查询的语句和索引进行了优化,情况得到缓解,但是需要进一步测试。
总结:
1.SQL语句是会影响到磁盘的消耗的,不当的语句会造成磁盘暴涨。
2.对查询语句需要仔细的规划,不要想当然的去定义一个查询语句,特别是在可以提供用户自定义查询的软件中。
3.仔细规划表索引。
如果有那位高人遇到过类似的问题,请给予您的建议。
Cause: The device on which the file resides is probably offline. If the file is a temporary file, then it is also possible that the device has run out of space. This could happen because disk space of temporary files is not necessarily allocated at file creation time.
Action: Restore access to the device or remove unnecessary files to free up space.
3.查看物理磁盘剩余空间还有20多个G,排除磁盘空间不足的原因。(我遇到的可能是磁盘空间不足的原因)。
4.查看各个数据文件大小:
SQL> SELECT bytes/1024/1024/1024 AS "大小(G)",NAME FROM v$datafile ORDER BY bytes;
大小(G) NAME
---------- --------------------------------------------------------------------------------
0.00488281 D:/ORACLE/ORADATA/KDC/TEMP02.ORA
0.01525878 C:/DATAFILE/KDCWZ_PLAN.ORA
0.01678466 D:/ORACLE/ORADATA/KDC/TOOLS01.DBF
0.01953125 D:/ORACLE/ORADATA/KDC/CWMLITE01.DBF
0.01953125 D:/ORACLE/ORADATA/KDC/DRSYS01.DBF
0.01953125 D:/ORACLE/ORADATA/KDC/ODM01.DBF
0.02441406 D:/ORACLE/ORADATA/KDC/INDX01.DBF
0.03723144 D:/ORACLE/ORADATA/KDC/XDB01.DBF
0.14587402 D:/ORACLE/ORADATA/KDC/EXAMPLE01.DBF
0.34765625 D:/DATAFILE/KDCWZ_BILL.ORA
0.41015625 D:/ORACLE/ORADATA/KDC/SYSTEM01.DBF
0.49328613 E:/DATAFILE/KDCWZ_STOCK.ORA
1.50741577 D:/ORACLE/ORADATA/KDC/UNDOTBS01.DBF
2.03735351 D:/ORACLE/ORADATA/KDC/USERS01.DBF
14 行 已选择
SQL> SELECT bytes/1024/1024/1024 AS "大小(G)",NAME FROM v$tempfile ORDER BY bytes;
大小(G) NAME
---------- --------------------------------------------------------------------------------
8.00000000 D:/ORACLE/ORADATA/KDC/TEMP01.DBF
看到系统中最大数据文件D:/ORACLE/ORADATA/KDC/TEMP01.DBF 大小为8G,初步估计是temp表空间无法扩展的原因。
5.重建temp表空间:
1.以sysdba身份登录
2.创建临时中转的临时表空间TEMP2
SQL> create temporary tablespace TEMP2 TEMPFILE D:/ORACLE/ORADATA/KDC/TEM
P02.DBF' SIZE 5M REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED
2 /
表空间已创建。
3.修改默认临时表空间为TEMP2
SQL> alter database default temporary tablespace temp2;
数据库已更改。
4.drop原来的临时表空间TEMP:
SQL> drop tablespace temp including contents and datafiles;
表空间已丢弃。
5.重新创建临时表空间TEMP:
SQL> create temporary tablespace TEMP TEMPFILE D:/ORACLE/ORADATA/KDC/TEM
P01.DBF' SIZE 5M REUSE AUTOEXTEND ON NEXT 640K MAXSIZE UNLIMITED
2 /
表空间已创建。
6.更改默认临时表空间为TEMP:
SQL> alter database default temporary tablespace temp;
数据库已更改。
7.drop临时表空间TEMP2
SQL> drop tablespace temp2 including contents and datafiles;
表空间已丢弃。
6.重新进入〔物资供应系统-调拨单下帐〕窗口,成功,问题解决!
--查找临时表空间
select * from database_properties
where property_name='DEFAULT_TEMP_TABLESPACE';
--查看临时表空间文件大小
select file_name,tablespace_name,bytes/1024/1024 "MB",autoextensible from dba_temp_files;
--sql语句
select * from v$sql;
--查找占用临时表空间的sql
Select se.username,se.sid,se.serial#,su.extents,su.blocks*to_number(rtrim(p.value))as Space,
tablespace,segtype,sql_text
from v$sort_usage su,v$parameter p,v$session se,v$sql s
where p.name='db_block_size' and su.session_addr=se.saddr and s.hash_value=su.sqlhash
and s.address=su.sqladdr
order by se.username,se.sid;