一个电信运营商客户的核心交易系统,临时表空间大量被占用,临时表空间被撑到了600GB。这样的问题复杂吗?取决于很多因素,不过今天所要讲的案例,并不复杂,如果我们对临时表空间在何种情况下使用有足够了解。
首先,我们要去检查是什么会话占用了临时表空间,具体占用了多少,临时段的具体类型是什么。正如我们要想知道这个月的花费过大,去分析原因时就要去看是哪些开销过大、开销了多少金额、开销的用途等。
这个步骤比较简单,查询v$sort_usage就可以了:
SQL_ID都是一样的,那这个SQL是否有其特殊性呢?SEGTYPE为SORT表明这个临时段是“排序段”,用于SQL排序,大小居然也是一样,会话占用的临时段大小将近1GB,几百个会话加在一起,想不让临时表空间不撑大都难。
看看这个相同的SQL ID代表的SQL是什么:
很明显,这是一条非常简单的SQL,没有ORDER BY ,也没有GROUP BY、UNION、DISTINCT等需要排序的,TABLE_XXX是一张普通的表,而不是视图。出现了什么问题?会不会是v$sort_usage的SQL_ID列有错误?我们查看其中一个会话正在执行的SQL:
v$sort_usage中看到某个会话当前没有执行任何SQL,v$sort_usage中的SQL_ID是该会话前一条执行的SQL。为什么这里显示的是会话前一条执行的SQL,关于这个问题后面再详述,但至少有一点是可以判断的:如果大量的临时段都是由会话当前正在执行的SQL所产生的,那说明同时有几百个会话在执行需要大量临时空间的SQL,那系统早就崩溃了。所以这些临时表空间的占用不应该是由当前在执行的SQL所产生的,至少大部分不是。
大部分人的一个错误观点是,临时表空间中当前占用的空间是由会话当前正在执行的SQL所产生的。上面的一个简单的分析判断,情况不应该是这样。我们可以基于查询类SQL的执行过程来分析:
解析SQL语句(Parse),生成一个游标(Open Cursor)。
执行SQL语句(Execute),严格说就是执行新产生的游标。
在游标中取数据(Fetch)。
关闭游标(Close Cursor)。
关键在第3步。大家都知道取数据有一个array size的概念,表示一次从游标中取多少条数据,这是一个循环的过程。如果SQL查询得到的数据有1000条,每次取100条,则需要取10次。对于Fetch Cursor,有两点:
一个游标,或者说一条SQL语句,并不要求客户端把所有数据取完,只取了一部分数据就关闭游标也是可以的。
只要还没有关闭游标,数据库就要维护该游标的状态,如果是排序的SQL,也需要维持该SQL已经排好序的数据。
很显然,从上述第2点可以知道,如果一条SQL使用了临时段来排序,在SQL对应的游标没关闭的情况下,Oracle数据库不会去释放临时段,因为对于Oracle数据库来说,它不会知道客户端是否还要继续取游标的数据。
基于这样的分析,我们只需要随便选择一个占用了接近1GB的会话,查询v$open_cursor,查看其打开的游标中是否有大数据量排序的SQL:
最后三个游标,实际上都是同一条SQL语句,排序的数据量最大,我们来看看这条SQL是什么:
基于为客户保密的原因,SQL做了处理,能知道这条SQL的确是排了序就行,不过在SQL中看不出来的是,这条SQL没有任何实质性的能够过滤大量数据的条件。那么我们count(*)这条SQL语句看看:
出来的结果居然有1200多万条数据,一个前台应用,不知道取1200多万条数据干嘛。但是从rows_processed/executions只有几万的结果来看,应用在取了几万条数据之后,由于某些原因(最大的可能就是不能再处理更多的数据),不再继续取数据,但是游标也一直没有关闭。
比较容易就能进行演示sort by时临时表空间的占用。
问题分析到这里,很明显确认的是,应用存在问题,也许是业务逻辑问题;也许是根据前台选择的条件拼接的SQL,但是没有任何条件时就查询了所有数据。接下来就是找来开发人员,至于后面的事就跟这个主题没有太大关系。我们可以根据这个案例来进一步展开,去探寻临时表空间的更多知识点。
这里要展开的第1点是,v$sort_usage中的sql_id是不是会话正在执行的SQL,我们去看看视图fixed_View_definition就知道了:
原来在v$sort_usage的定义中,就明确地说明了SQL_ID列是v$session中的prev_sql_id列,而不是当前的SQL。至于为什么这样定义,老实说,现在还不知道。
不过从11.2.0.2这个版本开始,v$sort_usage的基表x$ktsso中增加了一个字段ktssosqlid,表示该临时段真正关联的SQL,以上述的测试结果为例,查询这个基表的结果如下:
可以看到的是我们查询到了真正产生临时段的SQL。
一直以来,v$sort_usage中的SQL_ID误导了很多人。所幸的是Oracle从11.2.0.2开始进行了弥补,MOS中有文档:
我们改良一下v$sort_usage,使用如下的查询来代替:
要展开的第2点是,v$sort_usage中的SEGTYPE列的不同的值各有什么意义:
SORT:SQL排序使用的临时段,包括order by、group by、union、distinct、窗口函数(window function)、建索引等产生的排序。
DATA:临时表(Global Temporary Table)存储数据使有的段。
INDEX:临时表上建的索引使用的段。
HASH:hash算法,如hash连接所使用的临时段。
LOB_DATA和LOB_INDEX:临时LOB使用的临时段。
根据上述的段类型,大体可以分为三类占用:
SQL语句排序、HASH JOIN占用
临时表占用
临时LOB对象占用
临时表空间的异常占用,一种缓步增长的,另一种情况:一下撑满的通常是一个极大数据量的排序或极大的索引的创建。缓步增长的情况,跟系统的内存被逐渐占用类似,存在“泄露”。比如排序的SQL游标没有关闭,比如本文的案例;比如会话级临时表产生了数据后一直没有清除;临时LOB对象没有清理或泄露。前两种比较好去分析处理,但是临时LOB的泄露问题就复杂很多。
来看一个测试:
上述的代码执行完之后,在另一个窗口中,我们查询v$sort_usage:
可以看到,这个会话已经产生了类型为LOB_DATA的临时段。虽然SQL代码已经执行完成,会话已经处于空闲状态,但是临时段仍然存在着。
Oracle中的LOB变量,类似于C语句中的指针,或者类似于JAVA代码中的数据库连接Connection,是需要释放的。上述有问题的代码,缺少了释放LOB的代码:dbms_log.freetemporary(v_lob)。好在对于这种情况,Oracle提供了一个补救措施,就是设置60025事件可以自动清理掉不活动的LOB,只需要在参数文件中加上event='60025 trace name context forever'。
在Oracle数据库中,xmltype类型内部也实际上是LOB类型,xmltype类型的数据操作可能会产生较多的LOB临时段。lob类型的字段上的更改操作,比如lob拼接等,同样会产生LOB临时段。如果在v$sort_usage中发现大量的LOB类型的临时段,那么通常是由于代码存在问题,没有释放LOB,或者是由于Oracle本身的BUG。在MOS上,如果以lob temporary关键字搜索,会发现相当多的关于lob临时段的泄露或临时段没有释放相关的文档。
最后,不管是什么情况导致的临时表空间被过多占用,通常重启应用能够释放掉临时段,因为会话退出后,相对应的临时段就会被释放。看来,“重启”大法在这种情况下就很有用。
分享到:
相关推荐
3. AWR 报告的作用:AWR 报告可以显示占用临时表空间最高的 SQL 语句,但可能不准确体现出占用临时表空间最高的 SQL 语句。 4. 使用 shell 脚本来记录和分析临时表空间使用情况:可以编写 shell 脚本来记录使用临时...
DB2系统临时表空间过大可能引发严重的性能问题,这在实际操作中表现为SQL语句执行时间显著增加。本文以某银行的DB2数据库系统为例,深入探讨了如何诊断和解决此类问题。 首先,当遇到系统响应变慢、ACTIVE SESSION...
这些操作在处理大量数据时尤为常见,因此了解临时表空间的使用注意事项对于优化数据库性能至关重要。 首先,临时表空间是每个用户在Oracle数据库中进行操作时的默认工作区域。当用户进行如大型查询、创建索引或执行...
Oracle数据库在处理涉及排序、分组汇总和索引构建的操作时,会生成大量临时数据。例如,如果有一个员工信息表,记录按照创建时间排序,但...数据库管理员必须关注这些细节,以避免临时表空间设置不当导致的性能问题。
2. 表空间碎片化:当表空间中的数据被频繁地插入、删除和更新时,表空间可能会出现碎片化,占用大量的磁盘空间。 3. 表空间锁定:当多个事务同时访问同一个表空间时,可能会出现锁定问题,导致数据库性能下降。 三...
- 监控临时表空间的使用:通过数据库的自动工作负载存储库(AWR)或动态性能视图(如V$SORT_USAGE),可以监控临时表空间的使用情况,及时发现和处理潜在的问题。 6. Oracle数据库的管理:Oracle数据库的正常运行...
当临时表空间过大时,可能会导致数据库性能下降,甚至出现空间耗尽的问题。以下是一些解决临时表空间过大的策略和实现方法: 1. **分析临时表空间使用情况**: - 使用`V$TEMPSPACE_USAGE`视图来监控临时表空间的...
此命令用于创建一个名为 `temp1` 的新临时表空间,其中包含一个初始大小为 10MB 的临时文件。 #### 五、更改默认临时表空间 ##### 1. 查询当前默认临时表空间 ```sql SELECT * FROM database_properties WHERE ...
这种类型的临时表对于处理一次性数据非常有用,因为它们不会污染全局命名空间,也不会对其他用户产生影响。创建会话级临时表的步骤如下: 1. **创建临时表**:使用`CREATE GLOBAL TEMPORARY TABLE`语句创建临时表。...
- **全局临时表**(Global Temporary Table, GGT):不同于会话级临时表,全局临时表可以在整个数据库实例内共享,并且可以在提交或回滚事务后保留数据,直到下一次插入新数据覆盖为止。 #### 四、临时表的创建与...
在数据库管理中,数据存储效率和空间占用是一个关键问题,特别是在使用像Sybase这样的大型企业级数据库系统时。Sybase数据库在处理大量数据时,可能会出现数据空间占用过大的情况,这不仅会增加存储成本,也可能影响...
4. **清理机制**: 了解并正确使用临时表的自动清理机制,避免不必要的内存和磁盘空间占用。 #### 五、实例演示 以下是一个具体的实例,用于展示如何在SQL Server中创建和使用临时表: 1. **创建一个局部临时表**...
4. **减少资源消耗**:临时表只存在于内存中(在某些情况下可能会写入到磁盘的临时表空间),相对于常规表,对物理数据库资源的占用更少。 以下是一个简单的示例,展示了如何在存储过程中使用临时表返回结果集: `...
如果Temp表空间中有数据正在使用,则可以考虑创建一个新的临时表空间,并将其设置为默认的临时表空间,然后再删除旧的表空间。步骤如下: 1. **创建新表空间**: ```sql CREATE TEMPORARY TABLESPACE TEMP1 TEMP...
3. **收缩临时表空间**:当不再需要大量临时空间时,可以进行收缩操作。`SHRINK SPACE` 命令可以释放无用的空间,而 `KEEP` 参数则指定最小保留空间。例如,保持20MB的空间: ``` SQL> ALTER TABLESPACE temp ...
临时表的使用有时会产生非常大的临时表空间文件,尤其是在处理极端情况时,文件大小可能会暴涨至数百GB。为了避免这种情况,应该设置innodb_temp_data_file_path选项,以设定文件的最大上限,超过此上限时,应停止...
例如,可以使用临时表来分批处理大量数据,避免一次性加载大量数据导致的性能问题。此外,临时表也可以用于存储中间结果,以便在多个操作之间保持数据的完整性。 在使用临时表时,有一些最佳实践需要遵循: 1. 避免...
这段脚本首先定义了一个名为`@tb_size`的临时表,用于存放每个表的占用空间信息。接着使用`sp_msforeachtable`扩展存储过程遍历所有表,并对每个表执行`sp_spaceused`存储过程。最后,选择`@tb_size`中的所有记录...
标题中的问题涉及到数据库管理系统(DBMS)中一个常见的性能瓶颈:临时表空间不足。这个问题通常由复杂的SQL查询引发,特别是那些包含`DISTINCT`、`GROUP BY`和`UNION ALL`操作的查询。这些操作在执行时可能需要大量...
在数据库开发中,临时表空间是一个重要的概念,它主要用于处理数据库的排序操作以及存储临时表和中间排序结果等瞬时数据。临时表空间对于优化复杂的SQL查询至关重要,特别是涉及大量数据处理的情况。在MySQL中,临时...