Files
document-haness/docs/n+1liner/tech-log-studio/jpa-feed-query-performance/reference/reference-feed-visibility-query-pattern.md
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
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>
2026-09-04 22:51:59 +09:00

4.4 KiB

id, kind, slug, title, topic, topicName, project, status, studio
id kind slug title topic topicName project status studio
635fcedd-d402-4297-bcf3-9fcdf4200d28 REFERENCE feed-visibility-query-pattern Feed Visibility Query Pattern jpa-feed-query-performance JPA 피드 조회 성능 Liner N + 1문제 게시 전 https://hyeonworks.com/studio/documents/635fcedd-d402-4297-bcf3-9fcdf4200d28/edit

Feed Visibility Query Pattern

조회 사용자에 따라 보이는 항목이 갈리는 피드는 공개, 멘션, 비공개 세 분기를 만든다. 하나의 OR로 묶는 방식, 분기를 UNION으로 나누는 방식, 사용자별로 미리 계산하는 방식이 같은 결과를 다른 비용으로 만든다.

관계

  • Visibility OR이 Keyset Index를 깨뜨린 문제 단일 OR이 정렬 인덱스를 못 쓰는 것을 확인한 기록이다.
  • feed_visible을 Production CQRS로 승격할 것인가 사전계산 방식이 남긴 판단이다.
  • Keyset Pagination 설계 기준 이 조건과 함께 서야 하는 페이징 기준이다.

목적

세 분기는 조건의 성격이 다르다. 값 비교, 다른 테이블과의 관계 확인, 소유자 비교다. 하나의 인덱스는 하나의 선두 컬럼 순서만 주므로 셋을 한 접근 경로로 만족시킬 수 없다.

정렬과 페이징을 함께 요구하면 이 차이가 실행계획에서 드러난다.

규칙

1. 단일 OR은 정렬 순서를 잃는다

세 분기를 하나의 조건으로 묶으면 플래너가 분기별로 스캔한 뒤 bitmap으로 합친다. 이 과정에서 인덱스가 주던 순서가 사라져 상위 몇 행을 만들기 위한 정렬이 다시 필요해진다.

관계 확인 조건은 hashed SubPlan으로 처리될 수 있다.

2. UNION 분해는 분기마다 자기 인덱스를 태운다

세 분기를 각각 정렬이 보장되는 쿼리로 만들고 병합하면 전체 재정렬이 사라진다. 관계 확인 조건도 조인으로 바뀐다.

대신 요청할 때마다 세 분기를 각각 스캔한다. 분기 수만큼 접근이 늘어 buffers가 단일 OR보다 클 수 있다.

3. 사전계산은 조회를 단일 인덱스 스캔으로 바꾼다

사용자별로 볼 수 있는 항목을 미리 펼쳐 두면 조회는 커버링 인덱스 하나를 읽는다. OR도 조인도 정렬도 없다.

대신 원본이 바뀔 때 이 투영을 갱신해야 하고 사용자 수만큼 저장 공간이 늘어난다.

4. 세 방식이 같은 결과를 내는지 먼저 확인한다

실행계획을 비교하기 전에 같은 조회 사용자에게 같은 항목 집합이 나오는지 대조한다. 답이 다르면 비용 비교가 의미 없다.

5. 분기별 선택도에 맞는 인덱스를 따로 둔다

선택도가 낮은 분기는 전용 인덱스나 부분 인덱스가 유리하다. 관계 테이블은 조회 방향에 맞는 컬럼 순서가 필요하다.

부모를 찾는 인덱스와 조회자를 찾는 인덱스는 컬럼 순서가 다르다.

6. buffers만으로 우열을 정하지 않는다

UNION은 분기별 스캔 때문에 buffers가 클 수 있지만 전체 정렬을 없앤다. 무엇을 줄이려는지에 따라 선택이 달라진다.

훑는 후보 수, 정렬 유무, buffers를 함께 본다.

7. 사전계산을 상시 유지하면 읽기 모델이 된다

미리 계산한 테이블을 계속 유지하려면 원본 변경을 투영에 반영해야 한다. 이 시점에 조회 최적화가 아니라 읽기 모델 설계 문제가 된다.

적용 조건

  • 조회 사용자에 따라 보이는 항목이 달라지는 목록을 만들 때
  • 가시성 조건과 정렬·페이징을 함께 요구할 때
  • 고트래픽 읽기에서 조회 비용을 줄여야 할 때

예외

  • 분기가 하나뿐이면 단일 조건이 가장 단순하다. 이 기준은 분기가 셋 이상일 때 적용한다.
  • 쓰기가 잦고 읽기가 드물면 사전계산의 갱신 비용이 이득을 넘는다.
  • 조회 사용자 수가 매우 많으면 사용자별 투영의 저장 공간을 먼저 계산한다.

예시

  • 단일 OR : 분기별 스캔을 bitmap으로 합침, 정렬 재수행, 관계 조건은 hashed SubPlan
  • UNION 분해 : 분기별 정렬 스트림을 병합, 전체 재정렬 없음, 관계 조건은 조인
  • 사전계산 : 커버링 인덱스 하나, OR·조인·정렬 없음
  • 갱신 비용 : 사전계산만 있음
  • 저장 공간 : 사전계산은 조회 사용자 수에 비례