일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 그리드
- stream api
- MessageQueue
- 엑셀 업로드
- 보안
- spring
- ORM
- 자바8
- 자동빌드
- poi
- QueryDSL
- mom
- mssql
- Javascript
- DevOps
- sqlserver
- 제이쿼리그리드
- 대용량 업로드
- ci/cd
- JPA
- Stream
- docker
- Jenkins
- rabbitmq
- 자동배포
- java
- jqGrid
- 스트림
- apache.poi
- JQuery
- Today
- Total
개발 메모장
[Oracle] SQL 튜닝 본문
#. 다량의 데이터가 있는 테이블 또는 여러 테이블이 조인 돼있는 쿼리를 실행하면 속도가 느린 경우가 자주 발생하게 됩니다.
#. 쿼리가 실행될 때 최대한의 부담을 덜어줘야 DBMS도 최상의 성능을 발휘하여 우리가 원하는 값을 보여줄 것입니다.
#. 어떻게 해야 시스템이 부하가 걸리지 않고 빠른 응답을 할지에 대해 파악해보려 합니다.
1. Index 생성
- Where, Join On, Order by 절에서 자주 사용되고 수정하지 않는 컬럼을 파악하여 생성합니다.
- Index 생성에 사용한 컬럼은 되도록 Where 조건에 모두 사용하는 것이 좋습니다.
- 조건절에 >=, <=, Is Null, Is Not Null, In, Not In 등의 사용을 지양하고 가능한 = 로 정확한 데이터를 조회하도록 해줍니다.
- Example
- employees 테이블에 employee_id, department_id, salary 컬럼이 존재한다면 employee_id, department_id로 Index를 생성해 주는 것이 좋습니다.
- salary의 경우 월 단위 지급일 시 매달, 주 단위 지급일 시 매주 데이터가 들어오기에 적절치 않습니다.
CREATE INDEX idx_employee_id ON employees(employee_id);
CREATE INDEX idx_department_id ON employees(department_id);
2. Join이 필요 없는 경우 불필요한 조인하지 않기
- 조인이 필요 없는 경우 조인 테이블 배제하기
SELECT A.*
FROM TABLE1 A
INNER JOIN TABLE2 B ON A.COL1 = B.COL1
WHERE A.COL2 = 'TEST'
- 보다시피 Join을 했지만 Table1에 대한 조건만 걸려있어 Table2에 대한 Join은 불필요합니다.
- Table1의 Col2가 Table2에도 영향을 미처 조회해야 하는 데이터가 있는 경우엔 위와 같이 사용해야 하므로 확인을 정확히 한 뒤 필요한 내용만 추출해 조회합니다.
SELECT *
FROM TABLE1
WHERE COL2 = 'TEST'
3. 서브쿼리 최소화하기
- 서브쿼리는 쿼리 내부에 쿼리를 사용하여 해당 값을 가져오므로 복잡한 쿼리를 사용할 때엔 유용하지만 성능을 저하시키는 원인이 됩니다.
- 서브쿼리가 포함된 쿼리를 실행하면 두 번의 쿼리를 실행한다고 생각하면 되며 이로 인한 쿼리 처리 속도 또한 느려지게 됩니다.
SELECT *
FROM TABLE1
WHERE COL3 IN (
SELECT COL3
FROM TABLE2
WHERE COL4 = 'TT'
)
- 위와 같이 서브쿼리로 처리하는 방법보단 동일값을 갖는 컬럼이 양쪽 테이블 모두에 존재한다면 Join으로 처리하는 것이 좋습니다.
SELECT A.*
FROM TABLE1 A
INNER JOIN TABLE2 B ON A.COL3 = B.COL3
WHERE A.COL4 = 'TT'
4. OR보단 And 나 IN 사용하기
SELECT *
FROM TABLE1
WHERE COL1 = 'TT'
OR COL1 = 'EE'
OR COL1 = 'WW'
- 위 내용과 같이 COL1이 TT이거나 EE이거나 WW 일 경우의 데이터를 조회하게 됩니다.
- OR은 실행 시 UNION ALL로 변환되어 실행된다고 보면 되기에 눈에 보이지 않는 불필요한 요소까지 전부 실행되므로 좋지 않습니다.
- 차라리 IN을 사용하는 것이 더 낫습니다.
SELECT *
FROM TABLE1
WHERE COL1 IN ('TT', 'EE', 'WW');
5. IN, NOT IN보단 EXISTS, NOT EXISTS 사용하기
- EXISTS 문을 사용하면 서브쿼리를 사용하기에 더 성능이 안 좋을 것이라 생각이 듭니다.
- 하지만 쿼리 비용을 비교해 보면 IN을 사용했을 때가 더 많은 비용을 필요로 합니다.
- IN : COST = 5 / EXISTS : COST = 3
6. 조건 컬럼을 원형 그대로 사용하기
- 한마디로 좌변을 수정하는 경우는 지양해야 합니다.
- 좌변은 테이블의 많은 데이터 원본인데 이걸 수정하면 많은 데이터를 가공한 뒤 비교하게 되므로 성능이 떨어집니다.
- 차라리 우변을 가공하여 처리하는 것이 좋습니다.
SELECT *
FROM TABLE1
WHERE REPLACE(COL1, '-', '') = '20231205'
7. Distinct 사용하지 않기
- 중복된 내용을 제외하고 볼 때 사용하나 그렇게 보여주기 위해 내부적으로 처리되는 작업이 있습니다.
- 그렇기 때문에 간단히 조회하는 것 외에는 사용하지 않는 것이 좋습니다.
- Distinct 사용 시 Cost 값이 더 높게 나옵니다.
- Distinct 사용 시
- Distinct 미사용 시
8. Having 조건보단 Where 조건 사용하기
- Group by 사용할 때 조건절을 넣어야 하는 경우가 있습니다.
- 이때 Having보단 Where에 조건을 넣는 것이 비용 측면에서 유리합니다.
- Having 사용 실행계획을 보면 Filter를 한번 더 거치는 작업을 합니다.
- 그렇기 때문에 Cost 값이 더 높게 나옵니다.
- Having 사용 시
- Where 사용 시(인덱스를 타게 되어 더 낮아짐)
===========================================================
틀린 내용이 있거나 이견 있으시면 언제든 가감 없이 말씀 부탁드립니다!
===========================================================
'DBMS' 카테고리의 다른 글
[Oracle] WITH문 사용방법 (0) | 2024.04.08 |
---|---|
[MS-SQL] 마스킹 Function (0) | 2024.02.06 |
[MS-SQL] 프로시저 오류 발생 시 메일 발송(장단점, SMTP, 스케줄러) (0) | 2023.11.28 |
[Oracle] TimeStamp - 데이터 원복 (0) | 2023.11.23 |
[MS-SQL] SQL Server 로그인 계정 생성하기 (0) | 2023.11.22 |