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

简介: (原创转载请注明出处)   最近遇到一个语句,  只要一执行这个语句就会出现报错临时表空间不足,回想一下在语句中用到临时表空间无非是大量的SORT和HASH,然后通过执行计划查看如下:  PLAN_TABLE_OUTPUT------------------...
(原创转载请注明出处)
 
最近遇到一个语句,  只要一执行这个语句就会出现报错临时表空间不足,回想一下在语句中用到临时表空间无非是大量的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来改变小数据集为构造输入,而大数据集为探测输入来改变临时表空间不足的问题,同时提高性能。
相关实践学习
简单用户画像分析
本场景主要介绍基于海量日志数据进行简单用户画像分析为背景,如何通过使用DataWorks完成数据采集 、加工数据、配置数据质量监控和数据可视化展现等任务。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps 
相关文章
|
SQL 关系型数据库 MySQL
使用索引消除group by 排序
ySQL数据库在使用group by查询时默认会进行排序,有时候我们并不需要这种排序,消除这种排序有两种方式,本文介绍其中一种,即使用索引消除排序,这种方式还有一个附加的好处,就是避免临时表的创建。
555 0
|
SQL 存储 Oracle
table()函数的使用,提高查询效率
table()函数的使用,提高查询效率
174 0
table()函数的使用,提高查询效率
|
存储 关系型数据库 索引
Hash索引和B+树索引有什么区别或者说优劣势
Hash索引和B+树索引有什么区别或者说优劣势
398 0
|
SQL 监控 关系型数据库
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(五)
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(五)
144 0
|
关系型数据库 MySQL 索引
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(四)
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(四)
119 0
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(四)
|
关系型数据库 MySQL 索引
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(三)
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(三)
219 0
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(三)
|
关系型数据库 MySQL 索引
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(一)
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(一)
120 0
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(一)
|
SQL 关系型数据库 MySQL
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(二)
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(二)
143 0
MYSQL性能调优05_覆盖索引、索引下推、如何选择合适的索引、Order by与Group by优化、索引设计原则(二)
|
SQL Oracle 关系型数据库
Oracle中表连接方式(Nested Loop、Hash join)对于表访问次数的测试
介绍了sql多表连接的几种方式,如有不正确的地方请指正。
4258 0