一次HASH JOIN 临时表空间不足的分析和优化思路

(原创转载请注明出处)

 

最近遇到一个语句,  只要一执行这个语句就会出现报错临时表空间不足,回想一下在语句中用到临时表空间无非是大量的SORT和HASH,然后通过执行计划查看如下:
  PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3959216560

-------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name                    | Starts | E-Rows | A-Rows |   A-Time   |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------
|   1 |  HASH UNIQUE                         |                         |      1 |      4 |      0 |00:00:00.01 |       |       |  |
|   2 |   NESTED LOOPS OUTER                 |                         |      1 |      4 |      0 |00:00:00.01 |       |       |  |
|*  3 |    HASH JOIN                         |                         |      1 |      4 |      0 |00:00:00.01 |   703K|   703K|  |
|   4 |     NESTED LOOPS OUTER               |                         |      1 |      4 |   2524K|00:02:17.15 |       |       |  |
|   5 |      NESTED LOOPS                    |                         |      1 |      4 |   2524K|00:01:34.23 |       |       |  |
|*  6 |       HASH JOIN                      |                         |      1 |      4 |   2524K|00:00:53.84 |  2047M|    29M|   55M (1)|

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|*  7 |        HASH JOIN                     |                         |      1 |      4 |     11M|00:01:00.03 |  2797K|  1148K| 3144K (0)|
|*  8 |         TABLE ACCESS BY INDEX ROWID  | T_COMMISSION_FEE        |      1 |  25517 |  31948 |00:00:00.16 |       |       |  |
|*  9 |          INDEX RANGE SCAN            | PK_T_COMMISSION_FEE     |      1 |  25520 |  31948 |00:00:00.03 |       |       |  |
|* 10 |         HASH JOIN                    |                         |      1 |  33714 |     11M|00:00:12.24 |  1299K|  1299K| 1925K (0)|
|* 11 |          TABLE ACCESS FULL           | T_GL_BIZ_INTERFACE      |      1 |   7889 |  12414 |00:00:00.10 |       |       |  |
|* 12 |          TABLE ACCESS FULL           | T_BIZ_ACCOUNTING_INFO   |      1 |  32696 |  63896 |00:00:00.27 |       |       |  |
|  13 |        VIEW                          | VW_NSO_1                |      1 |      3 |      2 |00:00:00.01 |       |       |  |
|* 14 |         FILTER                       |                         |      1 |        |      2 |00:00:00.01 |       |       |  |
|* 15 |          CONNECT BY WITH FILTERING   |                         |      1 |        |      2 |00:00:00.01 |  9216 |  9216 | 8192  (0)|
|  16 |           TABLE ACCESS BY INDEX ROWID| test|      1 |        |      1 |00:00:00.01 |       |       |  |
|* 17 |            INDEX FULL SCAN           | tes123|      1 |      1 |      1 |00:00:00.01 |       |       |  |

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|  18 |           NESTED LOOPS               |                         |      2 |        |      1 |00:00:00.01 |       |       |  |
|  19 |            BUFFER SORT               |                         |      2 |        |      2 |00:00:00.01 |  9216 |  9216 | 8192  (0)|
|  20 |             CONNECT BY PUMP          |                         |      2 |        |      2 |00:00:00.01 |       |       |  |
|* 21 |            INDEX RANGE SCAN          | Ttest123|      2 |      3 |      1 |00:00:00.01 |       |       |  |
|  22 |           TABLE ACCESS FULL          | test|      0 |      3 |      0 |00:00:00.01 |       |       |  |
|  23 |       TABLE ACCESS BY INDEX ROWID    | test|   2524K|      1 |   2524K|00:00:30.72 |       |       |  |
|* 24 |        INDEX UNIQUE SCAN             | test123|   2524K|      1 |   2524K|00:00:12.32 |       |       |  |
|  25 |      TABLE ACCESS BY INDEX ROWID     | Ttt|   2524K|      1 |   2524K|00:00:31.35 |       |       |  |
|* 26 |       INDEX UNIQUE SCAN              | tet1|   2524K|      1 |   2524K|00:00:12.00 |       |       |  |
|  27 |     TABLE ACCESS FULL                | test31|      0 |     84 |      0 |00:00:00.01 |       |       |  |
|  28 |    TABLE ACCESS BY INDEX ROWID       | tes1234|      0 |      1 |      0 |00:00:00.01 |       |       |  |

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|* 29 |     INDEX UNIQUE SCAN                | PK_T_CONTRACT_MASTER    |      0 |      1 |      0 |00:00:00.01 |       |       |  |
-------------------------------------------------------------------------------------------------------------------------------------------

 

第6步太吓人了,我这个语句没有运行完因为会报错,这个状态应该是在故障点的,可以看到需要的HASH构造区域为2G,仔细分析下这个执行计划。
其实它是一个HASH JION和一个VIEW做的HASH JION,观察一下行数,就是11M(11*1024*1024)行和2行进行的一个HANSH JION,但是很奇怪的是执行
计划选择了大数据集为构造输入,构造输入在PGA的工作区的HASH_AREA_SIZE中建立一个HASH表,如果内存不够把HASH表存储在TMEP表空间里面,
而选择了小的数据集来作为探测输入,探测输入会通过连接条件通过HASH函数和HASH表进行比对,如果存在则输出,不存在则丢弃。下面我们通过
一个小小的试验来说明:
建立表
SQL> desc test;
Name  Type         Nullable Default Comments
----- ------------ -------- ------- --------
员工代码 NUMBER(20)   Y                        
员工中文名 VARCHAR2(50) Y                        
员工英文名 VARCHAR2(50) Y                        
归属机构 VARCHAR2(50) Y                        
岗位名称 VARCHAR2(50) Y     
SQL> select count(*) from test;
 
  COUNT(*)
----------
   3399680
   这个是大数据集
建立表
SQL> desc test2
Name Type       Nullable Default Comments
---- ---------- -------- ------- --------
员工代码 NUMBER(20) Y                        
工资 NUMBER(10) Y                        
 SQL> select count(*) from test2;
 
  COUNT(*)
----------
         3
 现在试验开始
 首先执行语句
 SQL> select  count(*) from test a,test2 b where a.员工代码=b.员工代码;

  COUNT(*)
----------
     15360

已用时间:  00: 00: 09.12

执行计划
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=ALL_ROWS (Cost=6098 Card=1 Bytes=
          14)

   1    0   SORT (AGGREGATE)
   2    1     HASH JOIN (Cost=6098 Card=13197 Bytes=184758)
   3    2       TABLE ACCESS (FULL) OF 'TEST2' (TABLE) (Cost=3 Card=3
          Bytes=21)

   4    2       TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=6063 Card=
          3409202 Bytes=23864414)

可以看到这个时候小数据集作TEST2为了构造输入,在执行期间通过语句
select operation_id,operation_type,actual_mem_used,tempseg_size,tablespace
from v$session s,v$sql_workarea_active w
where s.sid=w.sid
and S.SID=151;
得出的结果如下:
OPERATION_ID OPERATION_TYPE                           ACTUAL_MEM_USED TEMPSEG_SIZE TABLESPACE
------------ ---------------------------------------- --------------- ------------ -------------------------------
           2 HASH-JOIN                                         183296             
HASH JION用于构造HASH表使用内存183K没有使用临时表空间。

现在我们通过HINT来改变大数据集和小数据集的顺序,执行语句如下:
SQL> select  /*+ leading(a) use_hash(a b) */ count(*) from test a,test2 b where a.员工代码=b.员工代码;

  COUNT(*)
----------
     15360

已用时间:  00: 00: 13.82

执行计划
----------------------------------------------------------
   0      SELECT STATEMENT ptimizer=ALL_ROWS (Cost=10636 Card=1 Bytes
          =14)

   1    0   SORT (AGGREGATE)
   2    1     HASH JOIN (Cost=10636 Card=13197 Bytes=184758)
   3    2       TABLE ACCESS (FULL) OF 'TEST' (TABLE) (Cost=6063 Card=
          3409202 Bytes=23864414)

   4    2       TABLE ACCESS (FULL) OF 'TEST2' (TABLE) (Cost=3 Card=3
          Bytes=21)
这个时候TEST大数据集是构造输入,同样在执行期间通过语句得出结果
OPERATION_ID OPERATION_TYPE                           ACTUAL_MEM_USED TEMPSEG_SIZE TABLESPACE
------------ ---------------------------------------- --------------- ------------ -------------------------------
           2 HASH-JOIN                                        1205248     18874368 TEMP
 可以看到结果不同了,使用1.2M内存,使用临时表空间近19M。
 同时如果我们关注下以下信息:
 SQL> select * from v$sysstat where NAME LIKE '%workarea executions%';
 
STATISTIC# NAME                                                                  CLASS      VALUE    STAT_ID
---------- ---------------------------------------------------------------- ---------- ---------- ----------
       294 workarea executions - optimal                                            64       3525 3211650785
       295 workarea executions - onepass                                            64          4  798730793
       296 workarea executions - multipass                                          64          0 3804491469
 现在我们运行
 SQL>  select  /*+ leading(a) use_hash(a b) */ count(*) from test a,test2 b where a.员工代码=b.员工代码;

  COUNT(*)
----------
     15360
     在运行
  SQL> select * from v$sysstat where NAME LIKE '%workarea executions%';
 
STATISTIC# NAME                                                                  CLASS      VALUE    STAT_ID
---------- ---------------------------------------------------------------- ---------- ---------- ----------
       294 workarea executions - optimal                                            64       3525 3211650785
       295 workarea executions - onepass                                            64          5  798730793
       296 workarea executions - multipass                                          64          0 3804491469
 
可以看到workarea executions - onepass   增加了1说明我们进行了一次物理交换才完成了探测(还好没有多次)。

有了上面的试验,我的语句应该就可以通过HINT来改变小数据集为构造输入,而大数据集为探测输入来改变临时表空间不足的问题,同时提高性能。

时间: 2024-09-20 00:29:40

一次HASH JOIN 临时表空间不足的分析和优化思路的相关文章

itpub坛友问题--基于普通表或分区表创建索引,会占用临时表空间及何时回收临时表空间

个人简介: 8年oracle从业经验,具备丰富的oracle技能,目前在国内北京某专业oracle服务公司从事高级技术顾问.        服务过的客户:           中国电信           中国移动           中国联通           中国电通           国家电网           四川达州商业银行           湖南老百姓大药房           山西省公安厅           中国邮政           北京302医院         

Oracle临时表空间

当 Oracle 在执行一些 SQL 时,会需要一些临时空间来存储执行时产生的中间数据.这些临时空 间由 Orac le 从指定的临时表空间中分配给进程.主要有三种情况会占用临时空间:临时表/索引操作.排序和 临时 LO B 对象操作. A.临时表/索引: 在会话中,当第一次对临时表进行 INSERT(包括 CTAS)时 ,Orac le 会从临时表空间中为临时 表 及其索引分配临时空间一存储数据. B.排序: 任何会使用到排序的操作,包括 JOIN.创建(重建)INDEX.ORDER  BY.

oracle临时表空间大量占用问题的处理

一个电信运营商客户的核心交易系统,临时表空间大量被占用,临时表空间被撑到了600GB.这样的问题复杂吗?取决于很多因素,不过今天所要讲的案例,并不复杂,如果我们对临时表空间在何种情况下使用有足够了解. 首先,我们要去检查是什么会话占用了临时表空间,具体占用了多少,临时段的具体类型是什么.正如我们要想知道这个月的花费过大,去分析原因时就要去看是哪些开销过大.开销了多少金额.开销的用途等. 这个步骤比较简单,查询v$sort_usage就可以了: view plaincopy to clipboar

ORACLE临时表空间总结

临时表空间概念   临 时表空间用来管理数据库排序操作以及用于存储临时表.中间排序结果等临时对象,当ORACLE里需要用到SORT的时候,并且当PGA中 sort_area_size大小不够时,将会把数据放入临时表空间里进行排序.像数据库中一些操作: CREATE INDEX. ANALYZE.SELECT DISTINCT.ORDER BY.GROUP BY. UNION ALL. INTERSECT.MINUS.SORT-MERGE JOINS.HASH JOIN等都可能会用到临时表空间.当

初学Scala(1): Scala实现Hash Join

最近看了些Scala相关的内容,写了个简单的hash join. 初步实现 jion过程 从数据源读取两个List[List[Any]](),我把所有的操作都放到List容器里进行 将两份数据集,hash到自己写的简单的SimpleHashTable里,每次put进去的时候会返回一个Int值,用于记录两份数据占据的bucket number集合 由于两份数据都是基于同一个hash方法进行hash的,join具体发生在两个hashTable对应的bucket之间 遍历需要进行join的bucket

关于SQL执行计划错误导致临时表空间不足的问题_oracle

故障现象:临时表空间不足的问题已经报错过3次,客户也烦了,前两次都是同事添加5G的数据文件,目前已经达到40G,占用临时表空间主要是distinct 和group by 以及Union all 表数据量在200W左右,也不至于把40G的临时表空间撑爆. 原因分析:既然排序用不了这么多临时表空间应该是别的原因造成. 从包含故障时间段的AWR报告中可以看出这一阶段DBtime蛮高的,并且sql execute elapsed time 竟然占到了99.43%,可以断定是SQL语句引起的. 通过TOP

临时表空间的管理与受损恢复

      Oracle 临时表空间是Oracle数据库的重要组成部分,尽管该部分并没有cont体系结构上得以展现,但其重要地位也是不容忽视的.尤其是 对于大型的频繁操作,如创建索引,排序等等都需要在临时表空间完成来减少内存的开销.当然对于查询性能要求较高的应尽可能的避免在磁盘 上完成这些操作.本文主要描述的是临时表空间的管理与受损恢复. 一.临时表空间的特性与注意事项  1.特性        用户存储临时数据的表空间        临时数据通常只在一个数据库会话期间内存在的数据,分为两种形式

Oracle Temp临时表空间及其故障处理

 Oracle Temp临时表空间及其故障处理  Oracle 11g中Temp临时表空间.文件的新特性  临时表空间是Oracle体系结构中比较特殊的结构.通常情境下,数据库使用者只需要设置对应的临时表空间(到用户),临时段分配等工作都是系统自动完成.当临时数据不需要时,Oracle后台进程SMON也会负责将临时段回收. 在Oracle的备份恢复体系中,临时文件的地位比较低.在进行备份动作时,RMAN都不会进行临时文件恢复.在恢复启动过程中,如果发现临时文件不存在,通常Oracle也会自动将临

临时表空间组的使用

一个临时表空间组至少包含一个临时表空间. 临时表空间组无法显式创建,当第一个临时表空间分配给该组时自动创建,当组内所有临时表空间被移除时自动删除. 临时表空间组支持的操作: 可以将临时表空间从一个组移动到另外一个组(如果组不存在,则自动创建). 可以将组中的临时表空间从组中移除. 可以将目前不属于任何组的临时表空间加入一个组. 使用临时表空间组的好处: 防止一个临时表空间出现空间不足的问题. 同一个用户同时连接多个session时可以使用不同的临时表空间. 在并行操作中可以并行使用多个临时表空间