原本在9i上可以顺利完成的CTAS脚本,迁移到10g后运行总是报“ORA-1652: unable to extend temp segment by 128 in tablespace TS_HQY1_TEMP “无法扩展临时表空间的错误。应用人员表示该脚本涉及的数据量在迁移前后变化不大,而且令人匪夷所思的是在新的10g库上临时表空间大小已达40多个G,要远大于原9i库。很显然这不是由于临时表空间过小导致的该问题,更多的原因肯定是出在迁移后Oracle不同的行为方式上。

该脚本每月执行一次用以汇总数据,其中一个单表接近4亿行记录,GROUP BY操作涉及到的数据量十分庞大。我们来具体看一下这个SQL:

create table gprs_bill.zou_201007_cell_id as

select

calling_num mobile_number,

lac,

lpad(cell_id, 5, '0') cell_id,

count(*) c,

sum(call_duration) call_duration,

sum(decode(record_type, '00', 1, 0) * call_duration) moc_call_duration,

sum(decode(record_type, '01', 1, 0) * call_duration) mtc_call_duarion

from gprs_bill.g_all_cdr01

where substr(calling_num, 1, 7) in (select mobile_prefix from gprs_bill.zou_mobile_prefix)

group by calling_num, lac, lpad(cell_id, 5, '0');

SQL> set autotrace traceonly exp

SQL> select

2        calling_num mobile_number,

3        lac,

4        lpad(cell_id,5,'0') cell_id,

5        count(*) c,

6        sum(call_duration) call_duration,

7        sum(decode(record_type,'00',1,0)*call_duration) moc_call_duration,

8        sum(decode(record_type,'01',1,0)*call_duration) mtc_call_duarion

9   from gprs_bill.g_all_cdr01

10  where substr(calling_num,1,7) in (select mobile_prefix

11                                from gprs_bill.zou_mobile_prefix)

12  group by calling_num , lac , lpad(cell_id,5,'0');

Execution Plan

----------------------------------------------------------

Plan hash value: 212866585

--------------------------------------------------------------------------------

| Id  | Operation      | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time|

--------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT |     |   229K|  9880K|     |  1033K  (3)| 03:26:41 |

|   1 |  HASH GROUP BY  |     |   229K|  9880K|  22M| 1033K  (3)| 03:26:41 |

|*  2 |   HASH JOIN RIGHT SEMI|  |   229K|  9880K|     |1030K  (3)| 03:26:10 |

|   3 |    TABLE ACCESS FULL| ZOU_MOBILE_PREFIX|1692|13536||11 (0)|00:00:01 |

|   4 |    TABLE ACCESS FULL| G_ALL_CDR01 |388M | 13G| | 1026K  (2)| 03:25:21 |

--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("MOBILE_PREFIX"=SUBSTR("CALLING_NUM",1,7))

可以看到Oracle使用了HASH GROUP BY 算法以实现数据分组;HASH算法是10g中新引入的分组算法。

下面我们来详细介绍下10g中数据分组的改动:

在10g中GROUP BY操作仍将引发排序操作,但10g中引入了新的算法,这些算法都不保证返回的数据行有序排列;在10g中如果想保证”GROUP BY”后返回的数据有序排列则需要强制使用”ORDER BY”子句,这点和9i是截然不同的。若你没有指定”ORDER BY”子句,则不能保证返回的结果正确排序。

在10g中”GROUP BY”子句更倾向于使用一种HASH算法而非原先的SORT算法来分组数据,HASH算法的CPU COST要低于原先的SORT算法。但这2种算法在10g中都不保证返回数据正常排序,当采用SORT算法时可能”碰巧”出现返回正常排序数据的状况。

MOS建议,如果迁移中出现大量不利的变化,则可以通过修改参数来确保沿用原先的算法。但需要注意的是,即便采用了以下参数仍不能保证10g后”GROUP BY”后返回的数据如9i中那样排序,你需要做的是加入显式的”ORDER BY”子句以保证Oracle为你做到这一点。

alter session set "_gby_hash_aggregation_enabled" = false;

其中_gby_hash_aggregation_enabled隐式参数决定了Oracle是否可以启用新的HASH算法来进行数据分组(也适用于distinct等操作)。

对于以上说法我们通过实验进一步验证:

在11g中的测试如下:

SQL> select  * from v$version;

BANNER

----------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE    11.2.0.1.0      Production

TNS for 32-bit Windows: Version 11.2.0.1.0 - Production

NLSRTL Version 11.2.0.1.0 - Production

SQL> select  *  from youyus;

T1                 T2

---------- ----------

A                  10

B                  10

F                  30

G                  30

H                  40

I                  40

J                  40

L                  20

M                  20

已选择9行。

SQL>  analyze table youyus compute statistics for all columns;

表已分析。

SQL> set autotrace on;

SQL>  select t2,count(*) from youyus group by t2;

T2   COUNT(*)

---------- ----------

30     2

20     2

40     3

10     2

执行计划

----------------------------------------------------------

Plan hash value: 2940504347

-----------------------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time     |

-----------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     4 |     8 |     3  (34)| 00:00:01 |

|   1 |  HASH GROUP BY     |        |     4 |     8 |     3  (34)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| YOUYUS |     9 |    18 |     2   (0)| 00:00:01 |

-----------------------------------------------------------------------------

SQL> select t2,count(*) from youyus group by t2 order by t2;

T2   COUNT(*)

---------- ----------

10          2

20          2

30          2

40          3

执行计划

----------------------------------------------------------

Plan hash value: 1349668650

-----------------------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time     |

-----------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     4 |     8 |     3  (34)| 00:00:01 |

|   1 |  SORT GROUP BY     |        |     4 |     8 |     3  (34)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| YOUYUS |     9 |    18 |     2   (0)| 00:00:01 |

-----------------------------------------------------------------------------

SQL> alter session set "_gby_hash_aggregation_enabled" = false;

会话已更改。

SQL> select t2,count(*) from youyus group by t2;

T2   COUNT(*)

---------- ----------

10          2

20          2

30          2

40          3

执行计划

----------------------------------------------------------

Plan hash value: 1349668650

-------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Bytes | Cost  |

-------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     4 |     8 |    11 |

|   1 |  SORT GROUP BY     |        |     4 |     8 |    11 |

|   2 |   TABLE ACCESS FULL| YOUYUS |     9 |    18 |     2 |

-------------------------------------------------------------

Note

-----

- cpu costing is off (consider enabling it)

SQL> alter session set "_gby_hash_aggregation_enabled" =true;

会话已更改。

SQL> select t2,count(*) from youyus group by t2;

T2   COUNT(*)

---------- ----------

30          2

20          2

40          3

10          2

执行计划

----------------------------------------------------------

Plan hash value: 2940504347

-------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Bytes | Cost  |

-------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     4 |     8 |    10 |

|   1 |  HASH GROUP BY     |        |     4 |     8 |    10 |

|   2 |   TABLE ACCESS FULL| YOUYUS |     9 |    18 |     1 |

-------------------------------------------------------------

Note

-----

- cpu costing is off (consider enabling it)

9i上的表现如下:

SQL> select * from v$version;

BANNER

----------------------------------------------------------------

Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production

PL/SQL Release 9.2.0.4.0 - Production

CORE    9.2.0.3.0       Production

TNS for Linux: Version 9.2.0.4.0 - Production

NLSRTL Version 9.2.0.4.0 - Production

SQL> analyze table youyus_9i compute statistics for all columns;

Table analyzed.

SQL> select * from youyus_9i;

T1         T2

-- ----------

A          10

B          10

F          30

G          30

H          40

I          40

J          40

L          20

M          20

9 rows selected.

SQL> alter session set optimizer_mode=ALL_ROWS;

Session altered.

SQL> select t2,count(*) from youyus_9i group by t2;

T2   COUNT(*)

---------- ----------

10          2

20          2

30          2

40          3

Execution Plan

----------------------------------------------------------

0      SELECT STATEMENT Optimizer=ALL_ROWS (Cost=4 Card=4 Bytes=8)

1    0   SORT (GROUP BY) (Cost=4 Card=4 Bytes=8)

2    1     TABLE ACCESS (FULL) OF 'YOUYUS_9I' (Cost=2 Card=21 Bytes=42)

SQL> alter session set "_gby_hash_aggregation_enabled" =true;

alter session set "_gby_hash_aggregation_enabled" =true

*

ERROR at line 1:

ORA-02248: invalid option for ALTER SESSION

That's great!

应用脚本没有数据一定要正确排序的强制要求,但使用HASH GROUP BY算法后临时表空间的使用量大幅上升,远大于之前在9i上的使用量,最后导致语句无法顺利完成。首先想到的当然是通过修改_gby_hash_aggregation_enabled参数恢复到原先的SORT算法,并观察其临时表空间使用量:

SQL> alter session set "_gby_hash_aggregation_enabled"=false;

Session altered.

SQL> select

2  calling_num mobile_number,

3  lac,

4  lpad(cell_id,5,'0') cell_id,

5  count(*) c,

6  sum(call_duration) call_duration,

7  sum(decode(record_type,'00',1,0)*call_duration) moc_call_duration,

8  sum(decode(record_type,'01',1,0)*call_duration) mtc_call_duarion

9  from  gprs_bill.g_all_cdr01

10  where substr(calling_num,1,7) in (select mobile_prefix from gprs_bill.zou_mobile_prefix)

11  group by

12  calling_num ,

13  lac,

14  lpad(cell_id,5,'0');

Execution Plan

----------------------------------------------------------

Plan hash value: 4013005149

---------------------------------------------------------------------------------------------------

| Id  | Operation          | Name | Rows| Bytes |TempSpc| Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT |      |   229K|  9880K|     | 1033K  (3)| 03:26:41 |

|   1 |  SORT GROUP BY  |      |   229K|  9880K| 22M | 1033K  (3)| 03:26:41 |

|*  2 |   HASH JOIN RIGHT SEMI|    |   229K|  9880K|  |1030K  (3) | 03:26:10 |

|   3 |    TABLE ACCESS FULL| ZOU_MOBILE_PREFIX|1692|13536 ||11 (0)|00:00:01 |

|   4 |    TABLE ACCESS FULL| G_ALL_CDR01  |388M| 13G| |1026K (2)| 03:25:21 |

---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("MOBILE_PREFIX"=SUBSTR("CALLING_NUM",1,7))

create table gprs_bill.zou_201007_cell_id as

select

calling_num mobile_number,

lac,

lpad(cell_id,5,'0') cell_id,

count(*) c,

sum(call_duration) call_duration,

sum(decode(record_type,'00',1,0)*call_duration) moc_call_duration,

sum(decode(record_type,'01',1,0)*call_duration) mtc_call_duarion

from  gprs_bill.g_all_cdr01

where substr(calling_num,1,7) in (select mobile_prefix from gprs_bill.zou_mobile_prefix)

group by

calling_num ,

lac,

lpad(cell_id,5,'0');

可以看到在会话级别设置_gby_hash_aggregation_enabled为false后,Oracle不再采用10g中的HASH分组算法;因为该CTAS SQL脚本运行时间较长,我们通过动态视图V$SORT_USAGE来观察其运行期间的排序段使用量:

SQL> set time on;

14:30:59 SQL> select tablespace,contents,segtype,blocks*8/1024

2    from v$sort_usage

3   where username='GPRS_BILL';

TABLESPACE      CONTENTS  SEGTYPE   BLOCKS*8/1024

------------ ------------------ ------------------ -------------------------

TS_HQY1_TEMP   TEMPORARY     SORT            9349

14:35:59 SQL> /

TABLESPACE                      CONTENTS  SEGTYPE   BLOCKS*8/1024

------------------------------- --------- --------- -------------

TS_HQY1_TEMP                    TEMPORARY SORT              10011

15:02:46 SQL> select target ,totalwork,sofar,time_remaining,elapsed_seconds

2   from v$session_longops

3  where sofar!=totalwork;

TARGET     TOTALWORK      SOFAR TIME_REMAINING    ELAPSED_SECONDS

---------------- ---------- ---------- -------------- ---------------

GPRS_BILL.G_ALL_CDR01   5575890    5435796            143     5557

15:05:10 SQL> select target ,totalwork,sofar,time_remaining,elapsed_seconds

2    from v$session_longops

3   where sofar!=totalwork;

TARGET       TOTALWORK      SOFAR TIME_REMAINING ELAPSED_SECONDS

---------- ----------------- ------------ -------------------- ---------------

GPRS_BILL.G_ALL_CDR01    5575890    5562082       14            5692

15:05:13 SQL> select tablespace,contents,segtype,blocks*8/1024

2   from v$sort_usage

3  where username='GPRS_BILL';

TABLESPACE                      CONTENTS  SEGTYPE   BLOCKS*8/1024

------------------------------- --------- --------- -------------

TS_HQY1_TEMP                    TEMPORARY SORT              13835

15:12:22 SQL> select tablespace,contents,segtype,blocks*8/1024

2   from v$sort_usage

3  where username='GPRS_BILL';

TABLESPACE                      CONTENTS  SEGTYPE   BLOCKS*8/1024

------------------------------- --------- --------- -------------

TS_HQY1_TEMP                    TEMPORARY SORT              13922

该分组操作最后排序段使用量为13922MB,在客户可以接受的范围内。看起来新引入的HASH算法虽然有CPU成本低于SORT算法的优势,但可能消耗大量临时空间,可谓有得有失。

10g中HASH GROUP BY引起的临时表空间不足的更多相关文章

  1. 10g中注意谓词过滤的位置

    在10g中当主查询的谓词信息,被错误的放入子查询中,会导致子查询无法展开 explain plan for UPDATE DWF.F_PTY_INDIV O SET END_DT = TO_DATE( ...

  2. oracle临时表空间 ORA-01652:无法通过16(在表空间XXX中)扩展 temp 字段

    今天在查数据的时候报错  ORA-01652:无法通过16(在表空间temp1中)扩展 temp 字段 查看表空间使用明细 SELECT b.tablespace,        b.segfile# ...

  3. sql 提升查询效率 group by option hash group

    问题: 一个程序查询经常超过20siis限制时间,排查问题后发现其中的一个存储过程时间会在15s左右 解决思路: 1:确认问题点 通过输出时间的方式查看存储过程中每个部分的执行时间,找到最耗时的三个过 ...

  4. 如何在oracle中缩小临时表空间?ORA-01652无法在表空间中扩展temp

    查询临时表空间有多大: SQL> SELECT tablespace_name, file_name, bytes FROM dba_temp_files WHERE tablespace_na ...

  5. IOS9.0中hash值的bug与解决方案

    事件起因 事情是这样的:产品上线发布,突然出现了问题.运营Gg过来反应,当场给露珠演示,运营同事的手机是iphone,bug确实是存在的.奇怪的是露珠用了其他iphone手机(借别人的,露珠的是吊死安 ...

  6. 【python】正则中的group()

    来源:http://www.cnblogs.com/kaituorensheng/archive/2012/08/20/2648209.html 正则表达式中,group()用来提出分组截获的字符串, ...

  7. SqlServer中把结果集放到到临时表的方法

    一. SELECT INTO   1. 使用select into会自动生成临时表,不需要事先创建   select * into #temp from sysobjects   01. 把存储过程结 ...

  8. Linq中join & group join & left join 的用法

    Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报  分类: C#(14)  文章 ...

  9. 在oracle中,group by后将字符拼接,以及自定义排序

    1.在oracle中,group by后将字符拼接.任务:在学生表中,有studentid和subject两个字段.要求对studentid进行group by分组,并将所选科目拼接在一起.oracl ...

随机推荐

  1. C#保留小数位数

    1.System.Globalization.NumberFormatInfo provider = new System.Globalization.NumberFormatInfo(); prov ...

  2. poj 3114(强连通缩点+SPFA)

    题目链接:http://poj.org/problem?id=3114 思路:题目要求很简单,就是求两点之间的花费的最短时间,不过有一个要求:如果这两个city属于同一个国家,则花费时间为0.如何判断 ...

  3. 使用secureCRT远程Linux,出现远程主机拒绝连接

    1.查看是否开启远程连接, 控制面板->程序和功能->打开或关闭windows功能->勾选telnet服务器和telnet客户端2.cmd命令行输入telnet ip地址 端口号(比 ...

  4. JavaWeb项目开发案例精粹-第6章报价管理系统-05Action层

    0. <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC &quo ...

  5. 设计数据结构O1 insert delete和getRandom

    设计一个数据结构满足O(1)的insert, delete和getRandom.这个是从地里Amazon的面经中看到的. 我们可以使用一个resizable数组arr以及一个HashMap来完成. i ...

  6. Model元数据解析

    Model 元数据是针对数据类型的一种描述信息,主要用于控制数据类型本身及其成员属性在界面上的呈现方式,同时也为Model 绑定和验证提供必不可少的元数据信息.一个复杂数据类型通过属性的方式定义了一系 ...

  7. python抓取百度热词

    #baidu_hotword.py #get baidu hotword in news.baidu.com import urllib2 import os import re def getHtm ...

  8. Hibernate 异常 —— Unable to instantiate default tuplize

    出现这个异常 —— Unable to instantiate default tuplizer ,是 Hibernate 的映射文件(*.hbm.xml)导致的.仔细检查一下工程里的映射文件吧. 笔 ...

  9. linux系统的目录讲解

    还记得在前面介绍c h m o d命令时讲过,目录的权限位和文件有所不同.现在我们来看看其中的区别.目录的读权限位意味着可以列出其中的内容.写权限位意味着可以在该目录中创建文件,如果不希望其他用户在你 ...

  10. YTU 2614: A代码完善--系统日期

    2614: A代码完善--系统日期 时间限制: 1 Sec  内存限制: 128 MB 提交: 216  解决: 113 题目描述 注:本题只需要提交填写部分的代码,请按照C++方式提交. 已知某操作 ...