'grouping sets'에 해당되는 글 2건

  1. 2009.09.28 Temp Table Transformation 5
  2. 2009.07.06 간단한 집합개념 Test 7

오라클 Transformer 때때로 반복작업이 일어날경우 같은 테이블에 대한 부하가 심해지므로 TEMP 테이블을 만들어서 저장하고 테이블을 이용하여 반복적인 작업을 하게되는 경우가 있다. 대표적인 경우가 GROUPING SETS 사용하는 경우이다.

SELECT department_id, JOB_ID, AVG (salary) avg_sal

  FROM employee a

GROUP BY GROUPING SETS(department_id, JOB_ID)   ;

 

---------------------------------------------------------------+---------------------------+

| Id  | Operation                   | Name                     | Rows  | Cost  | Time      |

---------------------------------------------------------------+---------------------------+

| 0   | SELECT STATEMENT            |                          |       |    11 |           |

| 1   |  TEMP TABLE TRANSFORMATION  |                          |       |       |           |

| 2   |   LOAD AS SELECT            |                          |       |       |           |

| 3   |    TABLE ACCESS FULL        | EMPLOYEE                 |   107 |     3 |  00:00:01 |

| 4   |   LOAD AS SELECT            |                          |       |       |           |

| 5   |    HASH GROUP BY            |                          |     1 |     3 |  00:00:01 |

| 6   |     TABLE ACCESS FULL       | SYS_TEMP_0FD9D6608_434CFB|     1 |     2 |  00:00:01 |

| 7   |   LOAD AS SELECT            |                          |       |       |           |

| 8   |    HASH GROUP BY            |                          |     1 |     3 |  00:00:01 |

| 9   |     TABLE ACCESS FULL       | SYS_TEMP_0FD9D6608_434CFB|     1 |     2 |  00:00:01 |

| 10  |   VIEW                      |                          |     1 |     2 |  00:00:01 |

| 11  |    TABLE ACCESS FULL        | SYS_TEMP_0FD9D6609_434CFB|     1 |     2 |  00:00:01 |

---------------------------------------------------------------+---------------------------+

 

위의 PLAN 보면 먼저 ID 기준으로 3번에서 employee 테이블을 읽어서 필요한 컬럼만 TEMP 테이블에 저장해두고 그테이블을 반복해서 이용(ID 기준으로 6, 9, 11)하게 되는것이다. 그렇다면 3번이나 반복해서 temp 테이블을 사용하는걸까?

해답은 10053 trace 있다. id 기준으로 6번에 해당하는 SQL 아래와 같다. 

SELECT  /*+  */ NULL C0, C1 C1, BIN_TO_NUM(1, GROUPING(C1)) D0, COUNT(A0), SUM(A0)  FROM "SYS"."SYS_TEMP_0FD9D6608_434CFB" GROUP BY (C1)

 

위에서 C0, C1 TEMP 테이블의 컬럼 ALIAS 이며 각각 department_id, JOB_ID 의미한다. 또한 BIN_TO_NUM 함수를 사용한 이유는 나중에 ID 기준으로 11번째 에서 Group by 단위를 알아내기 위함이다. COUNT(A0), SUM(A0) select 한이유도 11번에서 AVG (salary) 값을 구하기 위해서이다. 참고로 avg(col1) 함수는 논리적으로 sum(col1)/count(col1) 같다.

또한 id 기준으로 9번에 해당하는 SQL 아래와 같다. 

SELECT  /*+  */ C0 C0, NULL C1, BIN_TO_NUM(GROUPING(C0), 1) D0, COUNT(A0), SUM(A0)  FROM "SYS"."SYS_TEMP_0FD9D6608_434CFB" GROUP BY (C0)

 
최종적으로 Transformation이 적용된 SQL은 다음과 같다.

with SYS_TEMP_0FD9D6608_434CFB as
   (
   SELECT department_id AS C0, JOB_ID AS C1, salary AS A0
     FROM employee a
   )  ,
   TEMP1 as
   (
    SELECT NULL C0, C1, COUNT(salary) AS A1, SUM(salary) AS A0
     FROM SYS_TEMP_0FD9D6608_434CFB
    GROUP BY C1
   ) ,
   TEMP2 as
   (
    SELECT C0, NULL C1, COUNT(salary) AS A1, SUM(salary) AS A0
     FROM SYS_TEMP_0FD9D6608_434CFB
    GROUP BY C0
   ) ,
  SYS_TEMP_0FD9D6609_434CFB AS
  (
   SELECT TEMP1. * FRPM TEMP1
   UNION ALL
   SELECT TEMP1. * FRPM TEMP1
  )
SELECT C0 AS DEPARTMENT_ID, C1 AS JOB_ID, A0 AS AVG_SAL
  FROM (SELECT C0, C1,
                       DECODE(A0, 0, TO_NUMBER(NULL), A1/A0) AS A0 --> 분모가 0 일 경우 처리
              FROM SYS_TEMP_0FD9D6609_434CFB )  ;



불만

id
기준으로 6번과 9번에서 각각 job_id department_id group by 해놓고 이것을 id 11 번에서 합쳐서 보여주게 된다. 하지만 필자는 이런 변환에 대하여 불만이 있다. 위의 쿼리는 EMPLOYEE 테이블을 GROUP BY 하지 않은 상태로 TEMP 테이블에 적재한다. 이것은 매우 비효율적이다. EMPLOYEE 테이블을 Temp 테이블에 적재시 미리 Group BY 하여 넣을 수가 있다. 아래의 SQL 처럼 미리 GROUP BY 하여 건수를 미리 줄여놓으면 반복작업시의 부하가 획기적으로 줄어들수 있기 때문이다.


select  department_id, JOB_ID, sum(sum_sal) / sum(cnt) as avg_sal 

from  (SELECT department_id, JOB_ID, count(salary) cnt, sum(salary) sum_sal

           FROM employee a

          GROUP BY department_id, JOB_ID  )

GROUP BY GROUPING SETS(department_id, JOB_ID)   ;

 

이렇게 수동으로 SQL 바꾸는 방법은 Grouping Sets 변환로직이 변하지 않는한 확실한 튜닝방법이 될수 있으므로 반드시 고려되어야 한다.

Posted by extremedb
,

pdf 첨부파일에 일부 오류가 있어 수정해서 다시올립니다. 또한 Rollup 의 개념을 추가 하였습니다.
댓글을 참조 바랍니다. (2009.07.17)


테스트의 이유
SQL이 절차적 언어와 비교할때 가장 두드러 지는 특징은 두가지 이다.
첫번째는 집합처리가 된다는 점이며 두번째로는 처리순서및 로직이 필요 없다는 것이다.
오늘은 첫번째 특징인 집합처리에 대해서 간단한 테스트를 진행하려 한다.
이 테스트를 통과한 사람은 집합개념이 확실한 사람이라고 보면 된다.
필자가 이러한 테스트를 하는 이유는 실무에서 Group By Extension(Rollup, Cube, Grouping Sets) 를 잘사용할경우 Union 등을 없애고 같은 테이블을 반복해서 Scan 하는 비효율을 줄일수 있기 때문이다. 이렇게 되려면 최소한 Group By Extension들의 개념을 확실히 알필요가 있다.

먼저 문법을 알아야 한다.
먼저 이 테스트를 진행하기전에 RollUp, Cube, Grouping Sets 를 모른다면 테스트를 진행할수 없으므로 문법책을 먼저 보고오기 바란다. 위의 3가지 문법을 모두 다 안다고 보고 테스트를 진행할것이다.

먼저 답을 내는 방법을 알아보자.
아래와 같이 문제에 답을 하면 된다.

문제 : 아래의 SQL 을 논리적으로 풀어서 나타내시오.

SELECT A, B, SUM(C)
  FROM T1
GROUP BY ROLLUP(A, B)



답변 :

SELECT A, B, SUM(C)
  FROM T1
GROUP BY A, B
UNION ALL
SELECT A, NULL, SUM(C)
  FROM T1
GROUP BY A
UNION ALL
SELECT NULL, NULL, SUM(C)
 FROM T1
GROUP BY NULL



위의 답은 문제의 SQL 을 논리적으로 풀어서 재작성 한것이다. 바로 Rollup 의 개념을 물어본 것이다.
이런식으로 답을 하면 된다. 간단하지 않은가?

이제 시작해보자.
문제는 4가지이며 모두 논리적으로 풀어서 작성하면 된다. 모든 문제는 3줄짜리 SQL 이다.
제약조건은 한문제를 푸는데 3분을 넘기면 안된다.

문제1 :
SELECT A, B, C, SUM(D)
  FROM T1
GROUP BY C, GROUPING SETS(A, B)

문제2 :
SELECT A, B, C, SUM(D)
  FROM T1
GROUP BY CUBE(  (A, B), C )

문제3 :
SELECT A, B, C, SUM(D)
  FROM T1
GROUP BY GROUPING SETS(A,B), GROUPING SETS(C,D)

문제4:
SELECT A, B, C, SUM(D)
  FROM T1
GROUP BY C, GROUPING SETS( ROLLUP(A), ROLLUP(B) )



모두 맟추면 집합개념이 확실한 사람...
위의 4가지 문제를 모두 쉽게 푸는 사람은 집합개념이 확실한 사람이라고 보면 된다.
만약 쉽게 떠오르지 않거나 머리가 아프다면 아직 문법을 모르거나 집합개념이 확실히 서지 않은 사람이라고 보면 된다.
문제가 어렵다고 너무걱정 하지말자. 아래의 자료에서 문제풀이를 보면서 개념정립을 하면 되기 때문이다.
답은 아래에 첨부된 파일에 존재한다.
개인적으로 Group By Extension을 정리한 문서이므로 자유로이 배포해도 된다.
하지만 배포 할때는 꼭 출처를 밝혀주기 바란다.
참고로 아래의 그림은 첨부된 파일의 한부분 이며 1번문제의 모범답안 이다.


사용자 삽입 이미지


invalid-file

Group By Extension 개념정리





편집후기 :
"과연 이런것 까지 알아야 하나" 라는 질문이 들어 왔다. 여러분들은 어떻게 생각하는가?
다음과 같은 한마디로 답변을 대신하고 싶다.
"SQL 문법과 집합개념은 SQL 튜닝의 시작점이다."

Posted by extremedb
,