SQL 작성 7거지악
좌변을 가공하지 않기
DB 인덱스를 사용할 수 없는 경우
- 인덱스 컬럼이 비교되기 전에 변형이 일어나는 경우
- 부정형으로 조건을 기술(not)한 경우
- 인덱스 컬럼이 NULL로 비교되는 경우
- 옵티마이저가 필요에 다라 상기 적용원칙을 준수했음에도 불구하고 특정 인덱스의 사용을 취사선택함으로써 사용되지 않는 경우
위와 같은 경우에 인덱스를 사용할 수 없습니다. 그렇기 때문에 DB 컬럼을 가공하지 말고 상수 부분을 가공해서 사용하도록 작성합니다.
잘못된 경우
-- 인덱스 컬럼에 변형이 일어났기 때문에 인덱스 사용이 불가
SELECT dept
, ename
, sal
FROM emp
WHERE SUBSTR(job, 1, 4) = 'SALE'
바람직한 경우
SELECT dept
, ename
, sal
FROM emp
WHERE job like 'SALE%'
데이터 존재 유무를 확인하기 위해 count(*) ... cnt > 0을 사용하지 않기
잘못된 경우
SELECT COUNT(*)
FROM tbl_point
WHERE user_id = 'id'
바람직한 경우
SELECT 1 AS cnt
WHERE EXISTS (
SELECT 'X'
FROM tbl_point
WHERE user_id = 'id'
)
Decode 혹은 Case를 사용할 때 새끼를 증손자 이상 만들지 않기
증손자 이상으로 Decode와 Case를 사용하게 되면 연산자 계산에 cost가 발생해서 속도가 떨어집니다.
CASE WHEN(
CASE WHEN(
CASE WHEN(...
)
)
Union을 사용할 때 다시 한 번 Union all로 사용할 수 없는지 확인하기
Union all은 두개의 결과값에서 중복되는 결과값까지 출력합니다. 반면에 Union은 두 개의 결과값에서 중복되는 결과값을 제거하고 출력합니다. Union은 중복되는 결과값을 제거하기위해 내부적으로 sort가 발생하면서 distinct가 발생합니다.
In Line View 또는 out of temp를 사용할 때 진정 필요한 In Line View인지를 확인하기
Query -> Parse -> Query Rewrite -> Query Optimization -> QEP Generation -> Query Execution -> Result
SQL이 실행되면 위와 같은 순서로 결과를 생성합니다. 위 순서에서 Query Rewrite 단계에서 서브질의와 뷰의 병합이 수행됩니다.
Query 원문
SELECT emp_no
FROM
(
SELECT
FROM emp
WHERE dept = ‘10’
)
WHERE emp_no > 20
Query Rewrite 단계
SELECT emp_no
FROM emp
WHERE dept = ‘10’
AND emp_no > 20
Join을 사용할 때 Relation 상 1:M, M:1, 1:1일 경우, 함부로 Outer Join을 사용하지 않기
Outer Join은 두 테이블 간의 관계에서 발생하는 조인 방식으로써 한쪽 테이블에 데이터가 없더라도 원래의 테이블 정보는 나오게 합니다. 이 때 Outer Join이 걸리는 테이블은 무조건 Full Table Scan이 발생합니다.
결과에만 만족하지 않고 실행계획에 관심을 가지고 절차형 로직을 버리고 집합적 하나의 SQL로 임무를 완수하기
모든 Query는 작성 후 실행계획을 확인해서 개발자가 원하는 형태로 수행이 되었는지 확인을 해 봐야 합니다. 인덱스가 생성 되어 있고 정상적인 연결고리로 조인이 이루어져도 옵티마이저에 의해 인덱스 취사와 같은 이유로 인덱스를 사용할 수 없는 경우도 발생할 수 있습니다. 그러므로 기본적으로 실행 계획은 확인하고 개발해야 합니다.