Tag: database
이 태그가 달린 글들 "database"
-
RDB Mastery #3 — EXPLAIN ANALYZE 마스터: Push Down 함정과 Index Selection 의 진짜 메커니즘
EXPLAIN ANALYZE 의 연산자 트리 한 줄을 읽을 줄 알면 옵티마이저의 결정을 직접 검증할 수 있습니다. Filter vs Index Range Scan over 한 단어 차이가 push down 성공 vs 실패. ANSI SQL 표준 row constructor (a,b)<(?,?) 가 MySQL 옵티마이저의 whitelist 패턴에 안 맞아서 push down 실패 — Bug #16247 은 2006년에 등록된 오래된 known limitation (현재 트래커는 duplicate 처리). Index Selection 도 옵티마이저의 cost-based 판단 — Q2 역설 (LIMIT 5 의 작은 수에서 옵티마이저가 잘못된 인덱스 선택해서 인덱스 추가가 느려짐). 100% 의 시간 옵티마이저는 옳지 않습니다. 1,000만 row 에서 측정한 5개 EXPLAIN ANALYZE 출력을 한 줄씩 해석하면서 push down 메커니즘과 cost-based index selection 의 내부를 풀어봅니다.
-
RDB Mastery #2 — MySQL 인덱스의 종류: B-tree / Hash / Covering / Composite / Multi-valued / Functional, 그리고 언제 무엇을 고를 것인가
InnoDB 의 모든 인덱스가 B-tree 가 아닙니다. Hash (Memory engine), Spatial (R-tree), Full-text (역인덱스), Multi-valued (8.0+, JSON 배열), Functional (8.0.13+, 표현식). 그리고 같은 B-tree 안에서도 clustered vs secondary, covering 여부, composite 의 leftmost prefix, cardinality / selectivity 가 결정의 축이 됩니다. 1,000만 row 환경에서 5종 인덱스를 직접 만들어 cardinality + Q1~Q5 latency 변화로 언제 무엇을 고를지를 측정으로 결정. Q3 covering 2,476배 / Q5 composite 577배 / Q2 역설 (인덱스 추가가 느려지는 케이스 0.66ms → 13.5ms). 인덱스는 공짜가 아닙니다 — 쓰기 비용 5~6배 + storage 1.3GB. 9개 다이어그램으로 끝까지 풀어봅니다.
-
RDB Mastery #1 — InnoDB 인덱스 내부 구조: No-Index 부터 다중 인덱스까지 B-tree 가 그리는 진짜 그림
인덱스를 안 걸어도 InnoDB 안에서는 이미 B-tree 입니다. PK 가 clustered index = 테이블 자체. Secondary index 는 PK 를 가리키는 별도 B-tree. Covering index 는 PK 까지 안 가도 답이 있는 인덱스. Reverse scan 은 leaf 의 양방향 linked list 를 거꾸로 walk. OFFSET 이 건너뛸 수 없는 이유는 B-tree 가 row 카운터를 안 가지기 때문. Cursor 가 빠른 이유는 WHERE 가 binary search primitive 를 트리거하기 때문. 다중 인덱스 = 같은 테이블에 N 개 B-tree. 1,000만 row 환경에서 [실측] Q3 covering 2,476배 / Q5 composite 577배 / OFFSET 1M 171ms / cursor 0.30ms — 다이어그램 10개로 끝까지 풀어봤습니다.
-
MySQL No-Offset Cursor 페이지네이션 — 1,000만 row에서 OFFSET 1M이 171ms / Cursor 0.30ms, 그 사이의 500배 함정 한 줄까지 측정으로 풀어봤습니다
1,000만 row 환경에서 OFFSET 1M이 171ms / No-Offset Cursor가 0.30ms — 약 570배 차이를 측정으로 재현했습니다. 그런데 No-Offset 코드를 어떻게 쓰느냐에 따라 또 한 번 500배가 갈라집니다. ANSI SQL 표준의 row constructor `(a,b)<(?,?)` 는 의미상 OR 분리 형태와 같지만 MySQL 옵티마이저가 index range로 push down 못 합니다 (154ms — OFFSET과 거의 동일). EXPLAIN ANALYZE 의 Filter: vs Covering index range scan over 한 줄 차이가 본질입니다 — 프로덕션 회고와 학습 환경 재현을 같이 풀어봤습니다.