1. INSERT 직후 UPDATE 하는 '이중 작업'을 CASE 문으로 통합하기
- ❌ 변경 전: 임시 테이블에 일단 데이터를 다 넣고(INSERT), 조건에 맞는 데이터만 다시 찾아서 수정(UPDATE)
- ✅ 변경 후: 데이터를 삽입(INSERT)하는 과정에서 SELECT나 VALUES 절 내에 CASE 문을 사용하여 조건을 평가해 한 번에 처리
- 💡 핵심: 디스크 I/O(읽고 쓰기)를 절반으로 줄이고, 대량 업데이트 시 발생하는 엄청난 양의 트랜잭션 로그 오버헤드를 방지하여 성능을 대폭 향상시킵니다.
2. 인덱스 컬럼 가공하지 않기 (좌항 날 것 유지)
- ❌ 변경 전: WHERE YEAR(JoinDate) = 2023 (인덱스가 걸린 컬럼 자체에 함수를 씌워버림)
- ✅ 변경 후: WHERE JoinDate >= '2023-01-01' AND JoinDate < '2024-01-01' (컬럼은 그대로 두고, 비교하는 우항의 값을 변경)
- 💡 핵심: 인덱스가 걸린 컬럼(좌항)을 함수나 연산으로 변형하면, 데이터베이스가 기껏 만들어둔 인덱스(사전)를 타지 못하고 테이블 전체를 처음부터 끝까지 뒤지는 '풀 테이블 스캔'을 해버립니다.
3. 존재 여부 확인 시 COUNT(*) 대신 EXISTS 사용하기
- ❌ 변경 전: IF (SELECT COUNT(*) FROM Orders WHERE CustomerID = 123) > 0 (조건에 맞는 데이터를 끝까지 다 세어봄)
- ✅ 변경 후: IF EXISTS (SELECT 1 FROM Orders WHERE CustomerID = 123) (데이터를 찾다가 하나라도 발견하면 즉시 종료)
- 💡 핵심: COUNT는 무조건 테이블을 끝까지 읽어 숫자를 합산하는 무거운 작업입니다. 존재 여부만 볼 때는 발견 즉시 스캔을 멈추는 EXISTS가 훨씬 가볍고 빠릅니다.
4. 중복 제거가 필요 없을 땐 무조건 UNION ALL 사용하기
- ❌ 변경 전: SELECT Email FROM A UNION SELECT Email FROM B (두 결과를 합친 후, DB 내부적으로 무거운 정렬 및 중복 제거 작업을 숨어서 수행)
- ✅ 변경 후: SELECT Email FROM A UNION ALL SELECT Email FROM B (정렬 없이 그냥 위아래로 데이터를 단순 병합)
- 💡 핵심: UNION은 중복을 제거하기 위해 데이터베이스에 엄청난 부하를 주는 정렬(Sort/Hash) 작업을 동반합니다. 두 데이터 셋에 중복이 없거나 중복되어도 상관없다면 반드시 UNION ALL을 써야 합니다.
5. 무의식적인 SELECT * 금지 (필요한 컬럼만 명시)
- ❌ 변경 전: SELECT * FROM CustomerOrders WHERE OrderDate = '2023-10-01' (실제로는 2개 컬럼만 쓰는데 50개 컬럼을 다 퍼옴)
- ✅ 변경 후: SELECT CustomerID, OrderAmount FROM CustomerOrders WHERE ... (화면이나 로직에 진짜 필요한 컬럼만 콕 집어서 명시)
- 💡 핵심: 안 쓰는 데이터까지 가져오면 불필요한 디스크 읽기, 메모리, 네트워크 대역폭 낭비가 발생합니다. 또한, 필요한 컬럼만 지정하면 테이블을 안 뒤지고 인덱스만 읽어서 결과를 뱉어내는 '커버링 인덱스'의 마법을 누릴 확률이 높아집니다.
6. LIKE 검색 시 와일드카드(%)는 문자열 뒤에만 사용하기
- ❌ 변경 전: WHERE Name LIKE '%김%' ('김'이 중간이나 끝에 있을지도 모르니 인덱스를 못 쓰고 전체 테이블을 다 뒤짐)
- ✅ 변경 후: WHERE Name LIKE '김%' ('김'으로 시작하는 것만 찾으면 되니 인덱스 사전에서 'ㄱ' 파트만 쏙 뽑아옴)
- 💡 핵심: DB의 인덱스는 국어사전처럼 '앞에서부터' 정렬되어 있습니다. %를 맨 앞에 두면 사전의 장점을 전혀 살릴 수 없습니다. 어쩔 수 없는 경우가 아니라면 와일드카드는 반드시 뒤에만 붙이세요.
'DB + SQL' 카테고리의 다른 글
| Scaler Subquery와 Subquery (0) | 2025.11.21 |
|---|---|
| [Oracle] - Oracle Package (0) | 2025.11.19 |
| Android에서 로컬 데이터베이스 접근하기 (0) | 2025.10.24 |
| java.sql.SQLSyntaxErrorException: Connection.setNetworkTimeout cannot be called on a closed connection (0) | 2025.09.08 |
| SQL - WITH 사용법 (1) | 2024.02.02 |