아래 두 방식으로 lock을 적용할 때 어떤 방식이 더 적절할까요?
transaction open
redis lock
redis unlock
transaction close
redis lock
transaction open
transaction close
redis unlock
답 보기
2번 상황이 더 적절하다. lock을 얻기 전에 transaction을 시작해버리면 connection pool이 낭비될 수 있기 때문이다.
MySQL bit 연산자 종류를 설명해보세요
답 보기
Name | Description |
---|---|
& | Bitwise AND |
| | Bitwise OR |
^ | Bitwise XOR |
~ | Bitwise NOT |
<< | Left shift |
>> | Right shift |
BIT_COUNT() | Return the number of bits that are set |
행기반(Row) 데이터베이스와 열기반(Column) 데이터베이스의 차이점은 무엇인가요?
답 보기
행기반 데이터베이스는 데이터를 메모리에서 행 단위로 연속적으로 저장해, 빠른 읽기/쓰기가 필요한 트랜잭션 처리(OLTP)에 유리합니다. 반면 열기반 데이터베이스는 데이터를 열 단위로 저장해, 분석 쿼리(OLAP)에서 필요한 열만 빠르게 읽을 수 있고, 압축 효율성이 좋습니다. 열기반은 대용량 분석에 적합하지만, 행기반은 트랜잭션 처리에 더 효과적입니다.
- 행(Row)기반 데이터베이스
-
특징
- 저장 구조: 데이터의 각 행(row)을 단위로 연속된 공간에 저장합니다. 즉, 한 행에 포함된 모든 컬럼 값들이 함께 저장됩니다.
- 사용 패턴: 한 번에 전체 행의 데이터를 읽거나 쓰는 경우가 많으며, OLTP(Online Transaction Processing)와 같이 빈번한 쓰기 작업, 레코드 단위의 조작이 중요한 환경에서 주로 사용됩니다.
-
장점
- 빠른 트랜잭션 처리: 한 레코드에 대한 읽기 및 쓰기 작업이 한 번에 이루어지므로, INSERT, UPDATE, DELETE와 같은 트랜잭션 처리에서 빠른 성능을 보입니다.
- 단순한 데이터 접근: 레코드 단위로 데이터를 다루므로, 응용 프로그램에서 데이터를 가져오거나 수정할 때 직관적입니다.
- 복잡한 트랜잭션 지원: ACID 특성을 잘 지원하여 복잡한 트랜잭션 환경에서 안정적인 성능을 보장합니다.
-
단점
- 분석 쿼리 비효율: 특정 컬럼에 대한 집계나 분석을 수행할 때, 필요한 컬럼만 읽어오는 것이 어렵고 전체 행을 읽어야 하므로 I/O 비용이 증가합니다.
- 캐시 활용의 한계: 필요한 데이터만 추출하기 어려워, 메모리 캐시에 불필요한 데이터까지 적재되는 경우가 발생할 수 있습니다.
- 열(Column)기반 데이터베이스
-
특징
- 저장 구조: 데이터의 각 컬럼(column)을 단위로 연속된 공간에 저장합니다. 즉, 동일 컬럼의 값들이 연속해서 저장됩니다.
- 사용 패턴: 대규모 데이터 분석, 집계, 리포팅 등 OLAP(Online Analytical Processing) 환경에서 주로 사용되며, 특정 컬럼만 선택하여 빠르게 읽어들일 수 있습니다.
-
장점
- 빠른 분석 쿼리 성능: 필요한 컬럼만 읽어오기 때문에 I/O 오버헤드가 줄어들고, 대량의 데이터를 빠르게 처리할 수 있습니다.
- 효율적인 압축: 동일 데이터 타입의 값들이 연속되어 저장되므로, 압축률이 높아 저장 공간을 절약할 수 있습니다.
- 벡터화 처리 지원: 대량의 데이터를 한 번에 처리하는 벡터화 연산에 유리하여, 병렬 처리 및 최적화된 분석 쿼리를 구현할 수 있습니다.
-
단점
- 트랜잭션 처리에 부적합: 레코드 단위의 빠른 쓰기 작업이 필요한 OLTP 환경에서는 오히려 성능이 저하될 수 있습니다. 개별 행을 재구성해야 하는 작업이 비효율적입니다.
- 데이터 업데이트 비용: 행 전체를 업데이트하는 대신 여러 컬럼에 분산되어 저장되어 있기 때문에, 한 행에 대한 업데이트 시 여러 영역을 수정해야 하여 비용이 발생할 수 있습니다.
- 구조 설계 복잡성: 데이터가 컬럼 단위로 분리되어 있으므로, 행 간 연관성을 고려한 쿼리를 작성하거나 조인 등의 작업 시 복잡도가 증가할 수 있습니다.
샤딩에 대해서 설명해주세요.
답 보기
- 사딩은 크게 수직 분할과 수평 분할로 나눔

- 수직 분할 한 스키마에 저장되어 있는 데이터를 특정 칼럼 단위로 잘라내어 분할 저장합니다. 수직 파티셔닝은 각 스키마를 나누고 데이터가 따라 옮겨갑니다.
결국 논리적 엔티티들을 다른 물리 엔티티들로 나누는 것을 의미합니다.
- 수평 분할 한 스키마에 저장되어 있는 데이터를 특정 알고리즘을 통해 행 단위로 잘라내어 분할 저장합니다. 수평 분할은 하나로 구성된 스키마를 동일한 구성의 여러 개의 스키마로 분리한 후, 각 스키마에 어떤 데이터가 저장될지를 샤드키를 기준으로 분리합니다.
- 샤딩 알고리즘
수평 분할을 통한 샤딩은 샤딩 알고리즘이 필요합니다. 기준이 되는 샤드키를 통해 어느 스키마에 접근하여 데이터를 핸들링할 것인지 정해야 하기 때문입니다. 한마디로 라우팅을 위한 알고리즘입니다.
- Modular Sharding

장점: Range 샤딩에 비해 데이터가 균일하게 분산됩니다. 단점: DB를 추가 증설하게 된다면 이미 적재된 데이터들의 재정렬이 필요합니다. (ex) (DB는 2개, 상품번호가 0~10까지 있을 경우) 상품번호 % 2 모듈러 연산 시 DB1에는 0,2,4,6,8,10 상품, DB2에는 1,3,5,7,9 상품이 들어가게 됩니다. Modular 샤딩은 데이터량이 일정 수준에서 유지될 것으로 예상되는 데이터 성격을 가진 곳에 적용할 때 어울리는 방식입니다.
실제적으로 상품 데이터를 적재하고 있으나, 해당 데이터는 장기적으로 미사용 할 경우 다른 디비에 옮겨 보관하기 때문에 적합합니다. 데이터가 꾸준히 늘어나더라도 적재속도가 그리 빠르지 않다면 문제없다고 합니다.
일단 데이터가 균일하게 분산된다는 점 자체가 트래픽을 안전하게 소화하면서도 DB 리소스를 최대한 활용할 수 있기 때문입니다.
- Range Sharding
Range 샤딩은 샤드키의 범위를 기준으로 DB를 선택하는 방식입니다.
장점: Modular 샤딩에 비해 증설에 재정렬 비용이 들지 않습니다. 단점: 일부 DB에 데이터가 몰릴 수 있습니다. Range 샤딩은 증설작업에 드는 비용이 크지 않습니다. Modular의 경우 증설작업이 진행될 경우 기존 데이터들도 모두 재정렬을 해야 합니다. 이런 부분에서 편합니다.
하지만 많이 접근하는 데이터가 있는 DB 쪽으로 트래픽이나 데이터량이 몰릴 수 있습니다. 결국 샤딩을 했더라도 동일한 현상이 나타난다면 또 부하 분산을 통해 DB를 쪼개 재정렬하는 작업이 필요하고, 반대로 트래픽이 저조한 DB는 통합 작업을 통해 유지비용을 아끼도록 관리해야 합니다.
- Reference : Gmarket Tech 샤딩이란 무엇인가 (opens in a new tab)
Named Lock이란 무엇이며, 어떻게 사용하나요?
꼬리 질문
- Named Lock과 다른 동시성 제어 방법들의 차이점은 무엇인가요?
- Named Lock을 사용할 때 주의해야 할 부하 관련 이슈는 무엇인가요?
답변 보기
✅ Named Lock은 이름 기반의 잠금 메커니즘으로, 특정 문자열을 키로 사용하여 동시성을 제어하는 방법입니다. MySQL의 GET_LOCK(), RELEASE_LOCK() 함수를 통해 사용할 수 있습니다.
-
사용법
- 획득:
SELECT GET_LOCK('lock_name', timeout)
- 해제:
SELECT RELEASE_LOCK('lock_name')
- 확인:
SELECT IS_FREE_LOCK('lock_name')
- 예시 코드:
-- Lock 획득 (10초 타임아웃) SELECT GET_LOCK('order_process_12345', 10); -- 비즈니스 로직 수행 UPDATE orders SET status = 'processing' WHERE id = 12345; -- Lock 해제 SELECT RELEASE_LOCK('order_process_12345');
- 획득:
-
장점
- 🎯 유연한 잠금 범위: 테이블/행 단위가 아닌 비즈니스 로직 단위로 잠금 가능
- ⚡ 빠른 성능: 메모리 기반으로 동작하여 디스크 I/O 없이 빠른 처리
- 🔧 간단한 구현: 별도의 인프라 없이 MySQL 함수만으로 구현 가능
- 🌐 분산 환경 지원: 여러 애플리케이션 서버에서 동일한 MySQL을 통해 동시성 제어
-
단점
- ⚠️ 수동 관리 필요: 개발자가 직접 Lock 획득/해제를 관리해야 함
- 🔗 Connection 종속성: Connection이 끊어지면 자동으로 Lock이 해제됨
- 📊 제한된 모니터링: Lock 상태를 추적하고 디버깅하기 어려움
- 💾 메모리 사용: 많은 Lock 사용 시 MySQL 메모리 사용량 증가
-
부하 관련 이슈
- Connection Pool 고갈: Lock을 오래 보유하면 Connection이 부족해질 수 있음
- Lock 대기 증가: 타임아웃 설정이 길면 대기 스레드가 늘어나 성능 저하
- 메모리 압박: 동시에 많은 Named Lock 사용 시 MySQL 메모리 부담
- 모니터링 어려움: 어떤 프로세스가 Lock을 보유 중인지 추적 곤란
-
대체 동시성 제어 장치
- Pessimistic Lock (비관적 잠금)
- DB 레벨에서 SELECT ... FOR UPDATE 사용
- 트랜잭션 내에서만 유효
- Optimistic Lock (낙관적 잠금)
- Version 컬럼을 이용한 충돌 감지
- 동시 수정이 적은 경우 효율적
- Redis 분산 락
- Redlock, Redisson 등 사용
- 별도 인프라 필요하지만 더 강력한 기능
- ZooKeeper
- 강력한 분산 조정 서비스
- 복잡하지만 안정적인 동시성 제어
- Pessimistic Lock (비관적 잠금)
-
꼬리질문: Named Lock과 다른 동시성 제어 방법들의 차이점은 무엇인가요?
- Pessimistic Lock과의 차이
- Named Lock: 애플리케이션 레벨, 이름 기반, Connection 종속
- Pessimistic Lock: DB 레벨, 행/테이블 기반, 트랜잭션 종속
- Optimistic Lock과의 차이
- Named Lock: 사전 차단 방식, Lock 대기 발생
- Optimistic Lock: 충돌 감지 방식, 재시도 로직 필요
- Redis Lock과의 차이
- Named Lock: MySQL 내장, 추가 인프라 불필요
- Redis Lock: 별도 Redis 필요, TTL 지원, 더 많은 기능
- Pessimistic Lock과의 차이
-
꼬리질문: Named Lock을 사용할 때 주의해야 할 부하 관련 이슈는 무엇인가요?
- Connection Pool 관리
- Lock 보유 시간 최소화 필요
- Pool 크기 적절히 설정 (Lock 대기 Connection 고려)
- 타임아웃 설정
- 너무 길면: 대기 스레드 증가로 시스템 부하
- 너무 짧으면: Lock 획득 실패로 재시도 증가
- 권장: 비즈니스 로직 수행 시간의 2-3배
- Lock 이름 관리
- 너무 세분화: 메모리 사용량 증가
- 너무 광범위: Lock 경합 증가
- 권장: 적절한 단위로 그룹핑 (예:
order_lock_{user_id % 100}
)
- 모니터링 구현
- Lock 획득/해제 로깅
- 장시간 Lock 보유 감지
- Connection Pool 사용률 모니터링
- Connection Pool 관리
Union 쿼리와 Union All의 차이에 대해서 설명해주세요.
꼬리 질문
- Union은 왜 중복을 제거하나요?
- Union All이 Union보다 빠른 이유는 무엇인가요?
답변 보기
✅ UNION
은 두 개 이상의 SELECT
문의 결과를 결합하면서 중복된 행을 제거하는 반면, UNION ALL
은 중복을 제거하지 않고 모든 결과를 그대로 반환합니다.
-
UNION
- 📜 기능: 여러
SELECT
문의 결과를 합칩니다. - 🗑️ 중복 제거: 결과 집합에서 중복된 행을 자동으로 제거합니다.
- 🐢 성능: 중복을 찾기 위해 내부적으로 정렬(Sort) 또는 해시(Hash) 작업을 수행하므로
UNION ALL
보다 느립니다. - 🤔 언제 사용?: 순수한 합집합(Set Union)이 필요할 때, 즉 중복이 없는 유니크한 결과만 원할 때 사용합니다.
- 📜 기능: 여러
-
UNION ALL
- 📜 기능: 여러
SELECT
문의 결과를 합칩니다. - ✨ 중복 허용: 중복된 행을 포함하여 모든 결과를 그대로 반환합니다.
- 🚀 성능: 중복 제거 과정이 없으므로
UNION
보다 훨씬 빠릅니다. - 🤔 언제 사용?: 중복된 결과가 상관없거나, 중복이 발생하지 않을 것이 확실할 때 성능상의 이점을 위해 사용합니다.
- 📜 기능: 여러
-
예시 코드
-- table_a: (1, 'A'), (2, 'B'), (3, 'C') -- table_b: (3, 'C'), (4, 'D'), (5, 'E') -- UNION (중복 '3, C'가 제거됨) SELECT * FROM table_a UNION SELECT * FROM table_b; -- 결과: (1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E') -- UNION ALL (중복 '3, C'가 포함됨) SELECT * FROM table_a UNION ALL SELECT * FROM table_b; -- 결과: (1, 'A'), (2, 'B'), (3, 'C'), (3, 'C'), (4, 'D'), (5, 'E')
-
꼬리질문: Union은 왜 중복을 제거하나요?
UNION
은 관계대수(Relational Algebra)의 합집합(Set Union) 연산에 기반을 두고 있기 때문입니다. 집합 이론에서 합집합은 중복된 원소를 포함하지 않는 것이 기본 원칙입니다. 따라서 SQL의UNION
도 이 원칙을 따라 중복을 제거합니다.
-
꼬리질문: Union All이 Union보다 빠른 이유는 무엇인가요?
UNION ALL
은 단순히 두 결과 집합을 위아래로 붙이기만 하는 반면,UNION
은 중복을 제거하기 위해 추가적인 작업을 수행해야 합니다.- 이 추가 작업은 보통 결과 집합을 정렬(Sorting)하거나 해시 테이블(Hash Table)을 만들어 중복 여부를 검사하는 과정이며, 이로 인해 상당한 오버헤드가 발생합니다. 따라서
UNION ALL
이 훨씬 빠릅니다.
Hash Join vs Merge Join vs Nested Loop Join 선택 기준
꼬리 질문
- Hash Join 선택 조건은 무엇인가요?
- Merge Join 선택 조건은 무엇인가요?
- Nested Loop Join 선택 조건은 무엇인가요?
- 각 조인 알고리즘의 동작 방식은 어떻게 되나요?
- 시간 복잡도는 어떻게 다른가요?
답변 보기
1. 🔎 각 Join 알고리즘의 상세 동작 방식
◆ Hash Join 🔨
Hash Join은 두 단계로 구성되어 동작합니다:
● Build Phase (구축 단계)
- 작은 테이블(Build Input)을 선택하여 메모리에 해시 테이블을 구축
- 조인 키를 해시 함수에 적용하여 버킷(bucket)에 분배
- 해시 테이블에는 해시값과 실제 행에 대한 포인터가 저장됨
- 메모리가 부족하면 일부 파티션을 디스크(tempdb)로 스필(spill)
● Probe Phase (탐색 단계)
- 큰 테이블(Probe Input)을 스캔하면서 각 행에 대해 동일한 해시 함수 적용
- 해시 테이블에서 매칭되는 버킷을 찾아 조인 수행
- 해시 충돌이 발생할 수 있으므로 실제 값 비교 필요
- 디스크로 스필된 파티션은 재귀적으로 처리
● Grace Hash Join 변형
- 메모리가 부족한 경우 사용되는 변형 알고리즘
- 양쪽 테이블을 모두 파티셔닝하여 디스크에 저장
- 각 파티션 쌍을 메모리에 로드하여 조인 수행
◆ Merge Join 🔄
Merge Join은 정렬된 입력을 효율적으로 병합합니다:
● 정렬 단계
- 양쪽 입력이 조인 키로 정렬되어 있지 않으면 먼저 정렬 수행
- 인덱스가 있으면 명시적 정렬 불필요 (Interesting Order)
- External Sort 알고리즘 사용 가능
● 병합 단계
- 두 정렬된 입력을 동시에 스캔
- 포인터를 사용하여 각 테이블의 현재 위치 추적
- 조인 키 값을 비교하여: • 같으면: 조인 결과 생성 • 왼쪽이 작으면: 왼쪽 포인터 전진 • 오른쪽이 작으면: 오른쪽 포인터 전진
- 양쪽 입력을 한 번씩만 스캔 (Single Pass)
◆ Nested Loop Join 🔁
Nested Loop Join은 가장 단순한 조인 알고리즘입니다:
● 기본 동작
- 외부 테이블(Outer Table)의 각 행에 대해
- 내부 테이블(Inner Table)을 전체 스캔하여 매칭 확인
- 이중 반복문(Nested Loop) 구조
● Index Nested Loop Join
- 내부 테이블에 인덱스가 있는 경우
- 전체 스캔 대신 인덱스 시크(Seek) 수행
- Correlated Parameter를 사용한 효율적 검색
- "Index Join"이라고도 불림
● Block Nested Loop Join (BNL)
- 메모리 버퍼를 활용한 최적화
- 외부 테이블의 여러 행을 버퍼에 저장
- 내부 테이블 스캔 시 버퍼의 모든 행과 비교
- MySQL 8.0.20부터는 Hash Join으로 대체
2. ✅ Hash Join 선택 조건 🔨
▪ Equality 조인만 필요한 경우 • Equi-join (=) 연산에 최적화 • 불평등 조인(>, <, !=)에는 부적합
▪ 정렬되지 않은 대용량 데이터 • 양쪽 테이블이 모두 큰 경우 효과적 • 정렬 비용을 피할 수 있음
▪ 충분한 메모리 확보 가능 • work_mem * hash_mem_multiplier 고려 • 메모리 부족 시 디스크 스필 발생으로 성능 저하
▪ 인덱스가 없거나 전체 스캔 필요시 • 인덱스 사용이 불가능한 상황 • Full Table Scan이 불가피한 경우
▪ 추가 선택 조건: • 조인 결과가 입력 크기에 비례할 때 • OLAP 쿼리나 배치 처리에 적합 • 병렬 처리 가능한 환경
3. ✅ Merge Join 선택 조건 🔄
▪ 범위 조건이 포함된 조인 • 부등호 조인 (>=, <=) 처리 가능 • 정렬된 데이터에서 범위 검색 효율적
▪ 양쪽 입력이 이미 정렬된 경우 • 인덱스로 인한 사전 정렬 (Interesting Order) • 추가 정렬 비용 없음
▪ Non-blocking 연산 필요시 • 첫 결과를 빠르게 반환 가능 • Pipelined 처리 가능
▪ ORDER BY 절이 있는 경우 • 조인 결과가 이미 정렬되어 있음 • 추가 정렬 단계 불필요
▪ 추가 선택 조건: • 양쪽 입력 크기가 비슷한 경우 • 메모리 사용량이 제한적인 환경 • 안정적이고 예측 가능한 성능 필요
4. ✅ Nested Loop Join 선택 조건 🔁
▪ 한쪽 테이블이 매우 작은 경우 • 외부 테이블의 행 수가 적을 때 • OLTP 쿼리에서 흔한 패턴
▪ 선택도 높은 인덱스 존재 • 내부 테이블에 효율적인 인덱스 • Index Seek 비용이 낮은 경우
▪ 첫 결과를 빠르게 반환 필요 Sort Merge Join이 더 느린 이유는 양쪽 스트림 동시 스캔이 필요하기 때문입니다. • 양쪽 테이블을 동시에 읽기 시작해야 함 • 첫 매칭 지점까지 양쪽을 진행시켜야 함
Sort Merge Join이 더 느린 이유
정확한 지적입니다! 제가 예시를 잘못 설명했네요. 핵심 차이는 "어떻게 12345 위치에 도달하는가"입니다.
Index Seek vs Index Scan의 근본적 차이 🎯
▪ Nested Loop Join - Index Seek 사용
B-tree Index 구조:
[Root]
/ \
[500] [10000]
/ \ / \
[100] [300] [5000] [12345] ← 직접 점프!
- B-tree를 타고 내려가 직접 점프
- O(log n) 시간 복잡도
- 12345 이전의 레코드들을 읽을 필요 없음
- 즉시 12345 위치 찾기 ⚡
▪ Sort Merge Join - Index Scan 사용
Index 순차 읽기:
[1] → [2] → [3] → ... → [12344] → [12345]
모든 엔트리를 순차적으로 읽어야 함
- 처음부터 순차적으로 스캔
- O(n) 시간 복잡도 (12345개 읽기)
- Sort Merge는 "zipper" 방식이라 순차 스캔 필요
- 12345까지 모든 레코드 읽기 🐢
▪ 실제 동작 차이
• Nested Loop:
- Customers 인덱스에서 바로 12345로 점프 (3-4번의 I/O)
- Orders 인덱스에서 customer_id=12345 바로 찾기
- 첫 결과 즉시 반환
• Sort Merge:
- Customers 인덱스 1부터 12345까지 순차 읽기
- Orders 인덱스도 병렬로 순차 읽기 시작
- 양쪽이 12345에서 만나면 결과 반환
▪ 왜 Sort Merge는 Seek를 못 쓰나? The merge join works well with both short OLTP queries and long OLAP ones. It's got linear complexity (both sets have to be scanned only once) - Sort Merge의 알고리즘 특성상 양쪽을 동시에 순차적으로 읽어야 하기 때문입니다. 중간에 점프하면 정렬 순서를 잃어버려 머지가 불가능합니다.
이것이 바로 **"첫 결과를 빠르게 반환"**에서 Nested Loop Join이 유리한 이유입니다!
• 전체 결과를 기다리지 않음 • 온라인 쿼리에 적합
▪ LIMIT 절과 함께 사용시 • 일부 결과만 필요한 경우 • Early termination 가능
▪ 추가 선택 조건: • 조인 조건이 복잡한 경우 • 불평등 조인이 유일한 옵션일 때 • Correlated Subquery 처리
5. 📊 시간 복잡도 비교
조인 알고리즘 | 시간 복잡도 | 공간 복잡도 | 특징 |
---|---|---|---|
Hash Join | O(M + N) | O(min(M,N)) | 해시 테이블 구축 비용 포함 |
Merge Join | O(M log M + N log N) → O(M + N)* | O(1)** | *이미 정렬된 경우, **추가 공간 |
Nested Loop | O(M × N) | O(1) | 인덱스 사용 시 O(M × log N) |
6. 🎯 실무 선택 가이드
◆ Query Optimizer의 자동 선택 • 통계 정보 기반 비용 추정 • Cardinality 예측 • Available Index 확인 • Memory Grant 계산
◆ 수동 힌트 사용 시 주의사항
-- SQL Server 예시
SELECT * FROM Table1
INNER LOOP JOIN Table2 ON ... -- Nested Loop 강제
INNER HASH JOIN Table3 ON ... -- Hash Join 강제
INNER MERGE JOIN Table4 ON ... -- Merge Join 강제
OPTION (FORCE ORDER)
⚠️ 주의: 데이터 분포가 변하면 성능 저하 가능
◆ 모니터링 포인트 • Hash Join: Memory Grant, Spill to TempDB • Merge Join: Sort 비용, Residual Predicate • Nested Loop: Inner Table Scan 횟수, Index Seek 비용
7. 🔄 Adaptive Join (SQL Server 2017+) • Runtime에 Hash Join과 Nested Loop 중 선택 • Batch Mode 처리 필요 • Columnstore Index와 함께 사용 • 실제 행 수에 따라 동적 전환
8. 💡 성능 최적화 팁
▪ 통계 정보 최신 유지
• UPDATE STATISTICS
정기 실행
• Auto Update Statistics 활성화
▪ 적절한 인덱스 설계 • 조인 키에 인덱스 생성 • Covering Index 고려
▪ 메모리 설정 최적화 • work_mem (PostgreSQL) • max_server_memory (SQL Server)
▪ 파티셔닝 고려 • 대용량 테이블 파티션 • Partition-wise Join 활용