The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4.9 KiB
id, kind, slug, title, topic, topicName, project, status, studio
| id | kind | slug | title | topic | topicName | project | status | studio |
|---|---|---|---|---|---|---|---|---|
| e8c2e9ea-cd87-46f8-9469-849dbd433d86 | REFERENCE | postgresql-query-plan-measurement | PostgreSQL Query Plan 측정 기준 | jpa-feed-query-performance | JPA 피드 조회 성능 | Liner N + 1문제 | 게시 전 | https://hyeonworks.com/studio/documents/e8c2e9ea-cd87-46f8-9469-849dbd433d86/edit |
PostgreSQL Query Plan 측정 기준
실행계획과 인덱스 동작을 측정하려면 운영과 같은 DB 엔진에서 재야 한다. 비용 모델, 통계, 저장 구조, 인덱스 기능이 엔진마다 달라서 다른 엔진의 계획을 그대로 옮겨 읽으면 체계적으로 틀린 결론에 이른다.
관계
- Query Plan은 실제 PostgreSQL에서 측정한다 이 기준에서 나온 결정이다.
- JPA N+1 정량 진단 기준 같은 측정에서 쿼리 수를 다루는 기준이다.
- ANALYZE 이후 Cardinality Estimate는 어떻게 달라지는가 통계 축에서 남은 질문이다.
목적
쿼리 수만으로는 보이지 않는 것이 있다. 한 쿼리가 실어 나르는 행수, 정렬 방식, 인덱스 사용 여부, 읽은 블록 수다.
이 값을 확인하려면 엔진이 실제로 고른 계획을 봐야 한다.
규칙
1. 운영과 같은 엔진에서 측정한다
비용 기반 옵티마이저는 가능한 계획의 비용을 추정해 고른다. 추정값도, 고를 수 있는 선택지도 엔진마다 다르다.
네 축이 갈린다. 비용 상수로 표현되는 비용 모델, 수집하는 통계의 종류, 저장 구조와 가시성 처리, 사용할 수 있는 인덱스 종류와 기능이다.
인메모리 대체 DB에서 재면 스캔 방식 선택이 뒤집히고, 한쪽에만 있는 접근 경로가 통째로 사라지며, 그 엔진 특유의 동작이 재현되지 않는다.
2. 스키마를 운영 마이그레이션과 같게 맞춘다
같은 마이그레이션을 적용하고 엔티티와 스키마의 불일치를 조기에 잡는다.
다만 스키마 검증만으로 모든 드리프트를 막을 수 없다. 인덱스 구성, 부분 인덱스 조건, check 제약, 외래키 삭제 정책, 컬럼 순서는 검증 범위 밖이므로 따로 확인한다.
3. EXPLAIN은 ANALYZE와 BUFFERS를 함께 쓴다
추정만으로는 실제 행수를 알 수 없다. 실제 실행 결과와 읽은 블록 수를 함께 본다.
4. 추정 행수와 실제 행수의 차이를 기록한다
둘이 크게 벌어지면 통계가 데이터 분포를 담지 못한 것일 수 있다. 대량 데이터를 넣은 직후에 특히 그렇다.
이 차이를 발견하면 통계를 갱신한 뒤 다시 측정하고 전후를 비교한다.
5. warm cache 결과를 cold 실행시간으로 읽지 않는다
읽은 블록이 모두 캐시에서 왔다면 디스크 접근이 없는 값이다. 캐시 상태를 함께 기록한다.
6. Execution Time을 애플리케이션 지연과 합산하지 않는다
Execution Time은 엔진 내부 시간에 가깝다. ORM 엔티티 생성, 결과 전달, DTO 매핑, 직렬화, HTTP를 포함하지 않는다. 같은 지표가 아니다.
7. 여러 방식을 비교할 때는 같은 실행에서 잰다
캐시 상태를 맞추려면 같은 테스트 실행 안에서 연속으로 측정한다. 실행을 나누면 캐시 차이가 비교에 섞인다.
8. 인덱스 의존을 확인하려면 토글한다
어떤 방식이 빠른 이유가 문법인지 인덱스인지 가르려면 인덱스를 제거한 뒤 같은 쿼리를 다시 잰다. 측정이 끝나면 복구한다.
9. 측정 도구의 정밀도를 주장 강도에 맞춘다
방향성만 확인하는 값에 더 엄밀한 도구를 붙인다고 근거가 강해지지 않는다. 오히려 측정보다 정밀한 결론처럼 보인다.
표본이 적으면 백분위수로 부르지 않고 중앙값과 최댓값으로 적는다.
10. 재현 조건을 함께 남긴다
이미지 태그보다 patch 버전이나 digest를 고정하는 편이 낫다. 측정 시작 시 엔진 버전과 주요 플래너 설정을 함께 기록한다.
적용 조건
- 인덱스 설계나 쿼리 형태를 바꾸고 효과를 확인할 때
- 스캔 방식이나 정렬 방식이 바뀌었는지 확인할 때
- 여러 SQL 표현의 비용을 비교할 때
예외
- 쿼리 발생 횟수만 확인하면 되는 단계에서는 실행계획까지 필요하지 않다.
- 운영 종단 지연이나 처리량이 필요하면 이 측정의 범위 밖이다. 부하 테스트와 APM으로 확인한다.
- 안정적인 꼬리 지연이 필요하면 반복 횟수를 크게 늘린 독립 세트가 필요하다.
예시
- 엔진 : 운영과 같은 것. 인메모리 대체 금지
- 명령 : EXPLAIN (ANALYZE, BUFFERS)
- 캐시 : warm인지 cold인지 기록
- 추정 vs 실제 : 차이가 크면 통계 갱신 후 재측정
- 비교 : 같은 실행 안에서 연속 측정
- 인덱스 의존 : DROP 후 재측정, 끝나면 복구
- Execution Time : 애플리케이션 지연과 다른 지표