본문 바로가기

Oracle/Tunning

[Oracle] sort group by, hash group by 차이

728x90

내부 Algorithm 

example table

CREATE TABLE t2 (id VARCHAR2(30), amount NUMBER);
INSERT INTO t2 VALUES ('A', 10);
INSERT INTO t2 VALUES ('C',  5);
INSERT INTO t2 VALUES ('B',  1);
INSERT INTO t2 VALUES ('B',  2);
INSERT INTO t2 VALUES ('A',  3);
INSERT INTO t2 VALUES ('C',  1);
INSERT INTO t2 VALUES ('A',  7);

SELECT id, sum(amount)
  FROM t2
 GROUP BY id;

 

Sort group by

전체 테이블을 group by 절의 컬럼으로 정렬 후 sub(amount) 같은 집계 함수를 실행한다.

ID   Amount SUM
A    10
A     3
A     7     10+3+7=20

B     1
B     2     1+2=3

C     5
C     1     5+1=6

 

Hash group by 

테이블을 한 번 스캔하고 각 행에 대한 해시 값을 계산한 다음 해당 행을 버킷(메모리 또는 디스크)에 넣는다.

SELECT id, ora_hash(id, 4), amount from t2;

ID Bucket  Amount  Hash table
A     2      10    Bucket#2: A=10
C     4       5    Bucket#4: C=5
B     2       1    Bucket#2: A=10, B=1
B     2       2    Bucket#2: A=10, B=1+2
A     2       3    Bucket#2: A=10+3, B=1+2
C     4       1    Bucket#4: C=5+1
A     2       7    Bucket#2: A=10+3+7, B=1+2

 

모든 값을 버킷에 넣은 후 해시 테이블을 스캔하여 집계를 계산한다.

Bucket#2: A=10+3+7, B=1+2
Bucket#4: C=5+1

 

성능

example big table 

CREATE TABLE t AS 
SELECT RPAD(object_type, 3000, 'x') as gby, o.* 
  FROM all_objects o WHERE rownum <= 50000; COMMIT;
INSERT INTO t SELECT * FROM t; COMMIT;
EXEC dbms_stats.gather_table_stats(user, 't');

 

 

/*+ use_hash_aggregation */  힌트를 사용해 hash group by 사용을 유도할 수 있다. 

SELECT /*+ USE_HASH_AGGREGATION */ gby, count(*)
  FROM t
 GROUP BY gby;

 

/*+ no_use_hash_aggregation */  힌트를 사용하면 sort group by 사용을 유도할 수 있다.

SELECT /*+ NO_USE_HASH_AGGREGATION */ gby, count(*)
  FROM t
 GROUP BY gby;

 

SELECT * FROM v$sql WHERE sql_text LIKE '%USE_HASH_AGGREGATION%'; 

SELECT * FROM v$sql_workarea WHERE sql_id IN ('663t56n1tdr59','fp5z7z1fyz42p');

OPERATION_TYPE  EST_OPT_SIZE LAST_MEM_USED ACTIVE_TIME MAX_TEMP
GROUP BY (HASH)       697344       1519616      325145        -
GROUP BY (SORT)       145408        129024      460975        -

 

 

GROUP BY HASH는 1519616바이트의 메모리가 필요하고 0.325145초 만에 실행된 반면, GROUP BY SORT는 캐시를 10분의 1 미만으로 사용했지만 약간 더 오래 실행되었다. 둘 다 메모리에서 완전히 실행되었다.

 

메모리가 부족해 디스크를 사용하게 된다면(여기서 메모리 제한을 인위적으로 낮추어 강제로 수행할 수 있음) max_tempseg_size 열의 값이 보인다.

 

ALTER SESSION SET workarea_size_policy = MANUAL;
ALTER SESSION SET sort_area_size = 10000;

OPERATION_TYPE  EST_OPT_SIZE LAST_MEM_USED ACTIVE_TIME  MAX_TEMP
GROUP BY (HASH)       697344        623616    22756184 268435456
GROUP BY (SORT)       103424         43008     1064479   4194304

 

 

만약 메모리가 부족해 disk를 사용한다면 HASH  GROUP BY 는 256MB 디스크가 필요하고 22.7초 만에 실행된 반면, GROUP BY SORT는 4MB 디스크만 필요하고 1.1초 만에 실행되었습니다. 즉 HASH GROUP BY는 Disk 가 사용되는 순간 성능이 매우 안좋아지는것을 확인할 수 있다.

 

 

728x90
반응형

'Oracle > Tunning' 카테고리의 다른 글

[Oracle] Fetch Call 최소화  (0) 2024.08.02
[Oracle] NL Join 확장 메커니즘  (0) 2024.03.22
[Oracle] SubQuery Hint  (0) 2024.02.22
[Oracle] 집계함수를 분석함수로 변경 튜닝  (0) 2024.02.21
[Oracle] Consistent vs Current 읽기  (0) 2023.08.11