부제목 : GBP (Group By Placement ) 의 목적및 용도
Parallel Query 수행시 Group by 를 먼저 수행하라(Group By Push Down) 라는 글에서 먼저 Group By 를 수행하여 성능을 향상시키는 경우를 설명하였다. 오늘도 Group By Push Dwon 과 아주 흡사한 Query Transformation 에 대하여 설명하려 한다.
Group By Push Down 은 Parallel Query 에서 한정적으로 나타나는 기능이지만 Group By Placement 는 이러한 제약이 없다. 또한 Group By Placement 는 Query Transformation 의 종류 이지만 Group By Push Down은 SQL 자체의 변환과정이 없다는 점에서 엄연히 다르다.
GBP 가 뭐하는 거지?
GBP 란 기본적으로 조인의 부하를 줄이기 위한 수단이다. 조인을 수행하기전에 Group By 를 먼저 수행하고 건수를 줄이고 난후에 조인을 수행함으로서 조인건수가 획기적으로 감소되게 하는데 그목적이 있다. 이 기능은 주로 OLTP 보다는 DW 의 대용량 Mart 등에서 사용할 경우 성능향상을 극대화 할수 있다. 아래의 SQL 을 보자.
환경 Oracle 11g (11.1.0.7)
SELECT /*+ qb_name(main) place_group_by(@main (S@main)) */
cust_city_id, SUM (quantity_sold)
FROM customers c, sales s
WHERE c.cust_id = s.cust_id AND s.cust_id BETWEEN 5000 AND 5500
GROUP BY c.cust_city_id ;
위의 SQL의 목적은 고객 테이블(customers)과 판매 테이블(sales)을 조인하여 고객의 도시별 판매수량을 구하는 것이다.
상식적으로는 ..
일반적인 상식으로는 customers 테이블과 sales 테이블을 조인한 후에 Group BY 가 한번 수행된다고 알고 있다. 하지만 Oracle 11g 로 넘어오면서 '상식의 파괴'가 일어난다.
--------------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 973 | |
| 1 | HASH GROUP BY | | 620 | 17K | 973 |
| 2 | HASH JOIN | | 7059 | 193K | 972 |
| 3 | VIEW | VW_GBC_1 | 7059 | 124K | 566 |
| 4 | HASH GROUP BY | | 7059 | 90K | 566 |
| 5 |
| 6 | TABLE ACCESS FULL |
| 7 | TABLE ACCESS FULL | CUSTOMERS| 54K | 542K | 405 |
--------------------------------------------+-----------------------------------+
Group By 가 두번 발생하다
위의 Plan 을 보면 Group By 가 두번 발생하였으며 조인도 sales 테이블을 Group By 한 이후에 발생하였다.
왜 두번 수행되나?
이것은 대용량 테이블인 sales 테이블을 먼저 조인 기준컬럼인 cust_id 로 먼저 Group By 하고 난후에 조인함으로서 조인의 부하를 줄이기 위함이다. 다시 말하면 오라클 Transformer는 SQL 을 아래와 같이 바꾼 것 이다.
FROM (SELECT s.cust_id item_1, SUM (s.quantity_sold) item_2
FROM sales s
WHERE s.cust_id <= 5500 AND s.cust_id >= 5000
GROUP BY s.cust_id) vw_gbc_1,
customers c
WHERE c.cust_id = vw_gbc_1.item_1
GROUP BY c.cust_city_id;
sales 테이블을 Group By 하여 인라인뷰를 먼저 만들고 customers 와 조인후 다시 c.cust_city_id 로 Group By 하고 있다. 인라인 뷰의 이름이 vw_gbc_1 인데 GBP 가 여러번 발생되면 vw_gbc_1, vw_gbc_2, vw_gbc_3 ... 처럼 숫자 부분이 증가 된다.
GBP 는 CBQT(Cost Based Query Transformation) 이다
Query Transformer 는 GBP 를 수행하기 위해 변환된(GBP 가 수행된) SQL 과 변환되지 않은 SQL을 각각 비용을 계산하여 가장 비용이 낮은 SQL 을 선택하게 된다. GBP 가 수행된 SQL 은 여러개 일수 있다.
아래는 작업을 수행하는 과정을 보여주는 10053 Trace 내용이다.
***********************************
Cost-Based Group By Placement
***********************************
GBP: Checking validity of GBP for query block
GBP: Checking validity of group-by placement for query block
GBP: Using search type: exhaustive
GBP: Considering group-by placement on query block
GBP: Starting iteration 1, state space = (1,2) : (0,0)
GBP: Transformed query
...중간생략
10053은 어렵지 않다
10053 을 어렵게 생각하는 DBA 들이 있다. 절대 어렵지 않다. GBP를 수행하기 위한 Using search type이 exhaustive 로 되어 있다. Using search type 이라는 것 은 변환 가능한 경우의 수를 어디까지 고려 할것인지 의 정도(level) 을 설명한 것이고 그 level 은 exhaustive 로 되어 있다. exhaustive 라는 것은 모든 변환가능한 경우의 수를 고려 하겠다는 뜻이다.
Iteration 이란 무엇인가?
Iteration 이란 CBQT 에서만 발생하며 기본적으로 변환이 수행된 경우와 수행되지 않은 경우의 Cost 를 비교하기 위한 경우의 수이다. 일반적으로 iteration 1 에서 변환이 수행되지 않은 경우를 나타내며 iteration 2 에서는 변환이 수행된 경우의 일련의 과정을 나타낸다. 마지막에는 iteration 1 과 iteration 2 의 Cost 를 비교하여 Cost 가 낮은 경우를 선택하게 된다.
Iteration 은 여러번 생길 수 있다
복잡한 SQL 의 경우 변환의 결과가 여러개 일수 있는데 이때는 Starting iteration 1, Starting iteration 2, Starting iteration 3 ... 등으로 증가한다. 하지만 원본 SQL 은 place_group_by 힌트를 사용하였으므로 GBP 를 수행한 경우(iteration 1)와 수행하지 않은 경우(iteration 2)의 Cost 를 비교하지 않고 iteration 1 에서 멈추게 된다.
GBP 를 Control 하자
GBP 를 Control 하는 파라미터는 _optimizer_group_by_placement 이며 Default 로 True 이다. 힌트는 GBP 를 강제하려면 place_group_by 헤제 하려면 no_place_group_by 힌트를 사용하면 된다.
결론
GBP 는 기본적으로 오라클이 자동으로 수행한다.
GBP 는 성능을 향상시키는 훌륭한 기능이지만 잘못 사용하면 오히려 독이 될수 있다. 조인을 먼저 수행하는 것이 오히려 결과 건수를 획기적으로 줄여주는 경우가 있는데 이런 경우는 GBP 를 사용하면 안된다. 이런 경우가 아니면서 조인하기 전에 먼저 Group By 하여 건수를 확실히 줄일수 있을때만 사용하여야 한다.
'Oracle > Optimizer' 카테고리의 다른 글
스칼라 서브쿼리를 서브쿼리로 변환하라 (11) | 2009.09.10 |
---|---|
Semi Join 의 재조명 (5) | 2009.08.31 |
Parallel Query 수행시 Group by 를 먼저 수행하라(Group By Push Down) (9) | 2009.08.12 |
11g DBMS_STATS 패키지 성능개선의 3가지 원리 (3) | 2009.06.15 |
PM ( Predicate Move Around ) : Where 조건을 다른뷰에 이동시켜라. (2) | 2009.06.09 |