2.7_CNT(Count(column)_To_Count(*))
2011.09.17 21:42
2.2.7 CNT - Cont(컬럼) 사용시 해당 컬럼이 Not Null인 경우 Count(*)로 대체하라.
-- Not Null 컬럼에도 불구하고 Cont(컬럼)을 사용하는 경우 Logical Optimazer는 Count(*) 로 변환
-- 인덱스 EMP_IDX_02 : JOB_ID, DEPARTMENT_ID
-- 제약조건 : LAST_NAME은 Not Null 컬럼
CREATE INDEX EMP_IDX_02 ON EMPLOYEE (JOB_ID, DEPARTMENT_ID);
ALTER SESSION SET EVENTS '10053 trace name context forever, level 1';
SELECT E.DEPARTMENT_ID, COUNT (E.LAST_NAME) CNT -- ①
FROM EMPLOYEE E
WHERE E.JOB_ID = 'ST_CLERK'
GROUP BY E.DEPARTMENT_ID;
ALTER SESSION SET EVENTS '10053 trace name context off';
DROP INDEX EMP_IDX_02;
------------------------------------------+-----------------------------------+
| Id | Operation | Name | Rows | Bytes | Cost | Time |
------------------------------------------+-----------------------------------+
| 0 | SELECT STATEMENT | | | | 1 | |
| 1 | SORT GROUP BY NOSORT | | 10 | 120 | 1 | 00:00:01 |
| 2 | INDEX RANGE SCAN | EMP_IDX_02| 20 | 240 | 1 | 00:00:01 | -- ②
------------------------------------------+-----------------------------------+
Predicate Information:
----------------------
2 - access("E"."JOB_ID"='ST_CLERK')
-- ① Count(컬럼) 사용 했으므로 테이블 액세스가 있어야 하지만
-- ② CNT 기능으로 Count(*)로 변환하여 Id2번 Index Scan 했다.
*************************
Count(col) to Count(*) (CNT)
*************************
CNT: Converting COUNT(LAST_NAME) to COUNT(*).
CNT: COUNT() to COUNT(*) done.
query block SEL$1 (#0) unchanged
Considering Query Transformations on query block SEL$1 (#0)
-- 인덱스 EMP_IDX_02 : JOB_ID, DEPARTMENT_ID
-- 제약조건 : LAST_NAME은 Null 허용 컬럼
CREATE INDEX EMP_IDX_02 ON EMPLOYEE (JOB_ID, DEPARTMENT_ID);
ALTER TABLE TLO.EMPLOYEE DROP CONSTRAINT EMP_LAST_NAME_NN;
EXPLAIN PLAN FOR
SELECT E.DEPARTMENT_ID, COUNT (E.FIRST_NAME) CNT
FROM EMPLOYEE E
WHERE E.JOB_ID = 'ST_CLERK'
GROUP BY E.DEPARTMENT_ID;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
ALTER TABLE TLO.EMPLOYEE ADD (
CONSTRAINT EMP_LAST_NAME_NN
CHECK (LAST_NAME IS NOT NULL));
DROP INDEX EMP_IDX_02;
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 190 | 2 (0)| 00:00:01 |
| 1 | SORT GROUP BY NOSORT | | 10 | 190 | 2 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMPLOYEE | 20 | 380 | 2 (0)| 00:00:01 | -- ② 테이블 액세스
|* 3 | INDEX RANGE SCAN | EMP_IDX_02 | 20 | | 1 (0)| 00:00:01 | -- ②
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."JOB_ID"='ST_CLERK')
-- 1. 물리 모델링 시에 Not Null 컬럼이라면 반드시 Constraint를 명시적으로 지정
-- 2. 될 수 있으면 Count(*)를 사용하라. SQL이 완벽하여 이러한 각종 Transformation 기능들이 추가적으로
실행되지 않도록 하는것이다. 이유는 Hard Parsing 시의 Query Transformation에 의한 부하 때문이다.
The Logical Optimizer (bysql.net 2011년 2차 스터디)
작성자: 김범석 (darkbeom)
최초작성일: 2011년 9월 17일
본문서는 bysql.net 스터디 결과입니다 .본 문서를 인용하실때는 출처를 밝혀주세요. http://www.bysql.net
문서의 잘못된 점이나 질문사항은 본문서에 댓글로 남겨주세요. ^^