- SMS_YN컬럼을 CHAR(1) 그리고 NULLABLE로 생성
SQL> CREATE TABLE TN_SNS (SMS_NO NUMBER <-- SMS 전송번호
,SMS_ID VARCHAR2(100) NOT NULL <-- SMS 전송ID
,SMS_YN CHAR(1)); <-- SMS 전송여부
- 전송해야 할 데이터를 테이블에 입력 할 때 SMS_YN을 NULL로 입력
SQL> INSERT INTO TN_SMS VALUES(1, 'Topsecret','');
SQL> COMMIT;
- SMS 전송해야 할 대상 추출
SQL> SELECT *
FROM TN_SMS
WHERE SMS_YN IS NULL;
- SMS 전송 후 전송 여부 업데이트
SQL> UPDATE TN_SMS
SET SMS_YN = 'Y'
WHERE SMS_NO = 1;
SQL> COMMIT;
SQL> CREATE TABLE NULL_T5
(C1 NUMBER
,C2 CHAR(1)
,C3 CHAR(1));
-- Data Insert
SQL> INSERT INTO NULL_T5
SELECT LEVEL
,CHR(65+MOD(LEVEL,26))
,DECODE(MOD(LEVEL,10000),9999,NULL,'Y')
FROM dual
CONNECT BY LEVEL <= 100000;
-- Key Commit
SQL> COMMIT;
-- Index
SQL> CREATE INDEX null_t5_idx_01 ON null_t5 (c3);
SQL> SELECT COUNT(*) AS c3_null_cnt
,(COUNT(*)/100000)*100 AS c3_null_ratio
FROM null_t5
WHERE c3 IS NULL;
C3_NULL_CNT C3_NULL_RATIO
----------- -------------
10 .01
SQL> SELECT *
FROM NULL_T5
WHERE C3 IS NULL;
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9 | 171 | 57 (4)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| NULL_T5 | 9 | 171 | 57 (4)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("C3" IS NULL)
개선방안
1. NVL처리와 Fucntion Based Index 생성
2. 컬럼속성변경(Default 설정)과 NULL 데이터 업데이트
3. 컬럼추가 및 인덱스 생성 후 WHERE절 변경
책 참조
(잘못된 예시로 예상 됨)
- Table의 컬럼 Default 변경
SQL> ALTER TABLE NULL_T5 MODIFY (C3 CHAR(1) DEFAULT 'N');
- NULL값을 Default값인 'N'으로 변경(운영 중일 경우)
SQL> UPDATE null_t5
SET c3 = 'N'
WHERE c3 IS NULL;
SQL> COMMIT;
- 실행계획 확인
SQL> SELECT *
FROM null_t5
--WHERE c3 is null
WHERE c3 = 'N';
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10 | 190 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| NULL_T5 | 10 | 190 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | NULL_T5_IDX_01 | 10 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("C3"='N')
Ex) t_u1(A,B,C) 인덱스 A, B, C일 경우
Case1)
SQL> SELECT *
FROM T
WHERE A=1
AND B=2;
Case2)
SQL> SELECT *
FROM T
WHERE A=1
AND C=2;
Case3)
SQL> SELECT *
FROM T
WHERE C=2;
- C4 신규 컬럼 추가
: 기존 컬럼 중 null이 없고, 임의로 조건을 추가해도 값이 변하지 않는 컬럼이 이미 존재한다면, 꼭 신규 컬럼을 만들 필요 없음
SQL> ALTER TABLE null_t5 ADD (c4 CHAR(3) Default 'ALL');
- 기존 인덱스 변경 (C3 --> C4, C3)
SQL> DROP INDEX null_t5_idx_01;
SQL> CREATE INDEX null_t5_idx_01 ON null_t5 (c4, c3);
- 실행계획
SQL> SELECT *
FROM null_t5
WHERE c4 = 'ALL'
AND c3 IS NULL;
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 120 | 121 (2)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| NULL_T5 | 5 | 120 | 121 (2)| 00:00:02 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("C3" IS NULL AND "C4"='ALL')