메뉴 건너뛰기

bysql.net

2.7_CNT(Count(column)_To_Count(*))

2011.09.18 06:42

darkbeom 조회 수:2066

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
문서의 잘못된 점이나 질문사항은 본문서에 댓글로 남겨주세요. ^^