10g中HASH GROUP BY引起的临时表空间不足
原本在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引起的临时表空间不足的更多相关文章
- 10g中注意谓词过滤的位置
在10g中当主查询的谓词信息,被错误的放入子查询中,会导致子查询无法展开 explain plan for UPDATE DWF.F_PTY_INDIV O SET END_DT = TO_DATE( ...
- oracle临时表空间 ORA-01652:无法通过16(在表空间XXX中)扩展 temp 字段
今天在查数据的时候报错 ORA-01652:无法通过16(在表空间temp1中)扩展 temp 字段 查看表空间使用明细 SELECT b.tablespace, b.segfile# ...
- sql 提升查询效率 group by option hash group
问题: 一个程序查询经常超过20siis限制时间,排查问题后发现其中的一个存储过程时间会在15s左右 解决思路: 1:确认问题点 通过输出时间的方式查看存储过程中每个部分的执行时间,找到最耗时的三个过 ...
- 如何在oracle中缩小临时表空间?ORA-01652无法在表空间中扩展temp
查询临时表空间有多大: SQL> SELECT tablespace_name, file_name, bytes FROM dba_temp_files WHERE tablespace_na ...
- IOS9.0中hash值的bug与解决方案
事件起因 事情是这样的:产品上线发布,突然出现了问题.运营Gg过来反应,当场给露珠演示,运营同事的手机是iphone,bug确实是存在的.奇怪的是露珠用了其他iphone手机(借别人的,露珠的是吊死安 ...
- 【python】正则中的group()
来源:http://www.cnblogs.com/kaituorensheng/archive/2012/08/20/2648209.html 正则表达式中,group()用来提出分组截获的字符串, ...
- SqlServer中把结果集放到到临时表的方法
一. SELECT INTO 1. 使用select into会自动生成临时表,不需要事先创建 select * into #temp from sysobjects 01. 把存储过程结 ...
- Linq中join & group join & left join 的用法
Linq中join & group join & left join 的用法 2013-01-30 11:12 12154人阅读 评论(0) 收藏 举报 分类: C#(14) 文章 ...
- 在oracle中,group by后将字符拼接,以及自定义排序
1.在oracle中,group by后将字符拼接.任务:在学生表中,有studentid和subject两个字段.要求对studentid进行group by分组,并将所选科目拼接在一起.oracl ...
随机推荐
- VS2012简单的使用感受+插件推荐
VS2012简单的使用感受+插件推荐http://www.cnblogs.com/tangge/archive/2013/03/12/2955367.html
- hdu 4753 Fishhead’s Little Game 博弈论+记忆化搜索
思路:状态最多有2^12,采用记忆化搜索!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm& ...
- opengl还有地方要写
今天先到这吧... 别忘记了,明天补上! 2014.3.10
- React 万能的函数表达式
一.语法简介 表达式可以以下两种方法, (1)(function A(){})(this),(this)参数在函数外面 (2)(function B(){}(this)),(this)参数在函数里面 ...
- 【转】RESTful Web Services初探
近几年,RESTful Web Services渐渐开始流行,大量用于解决异构系统间的通信问题.很多网站和应用提供的API,都是基于RESTful风格的Web Services,比较著名的包括Twit ...
- AlarmManager.RTC和ELAPSED_REALTIME的区别
AlarmManager.RTC,硬件闹钟,不唤醒手机(也可能是其它设备)休眠:当手机休眠时不发射闹钟. AlarmManager.RTC_WAKEUP,硬件闹钟,当闹钟发躰时唤醒手机休眠: Alar ...
- 最短路径BellmanFord , Dijsktra
最短路径算法也是常用的图算法,在网上看到了一份c的代码,写的很清楚,今天有空给写成java的了,就当练手了.另,算法导论362页详细介绍了Bellman-Ford算法,本来打算再写个Dijsktra算 ...
- HDU 4630 No Pain No Game 树状数组+离线查询
思路参考 这里. #include <cstdio> #include <cstring> #include <cstdlib> #include <algo ...
- 《Linux内核设计与实现》读书笔记(十)- 内核同步方法【转】
转自:http://www.cnblogs.com/wang_yb/archive/2013/05/01/3052865.html 内核中提供了多种方法来防止竞争条件,理解了这些方法的使用场景有助于我 ...
- 10.cadence.自定义焊盘的创建[原创]
一.自定义图形焊盘 1.设置环境(面板大小,格点) --- ------ 圆形 Shape > Circular ---- 两个DRC错误,证明图形重合了, 将图形复合一下: --- 椭圆类焊盘 ...