Skip to content

post_likes break-even 재측정: PK 길이 증가에 따른 secondary 개수/데이터 양 손익분기 정량화 #68

@seonghooncho

Description

@seonghooncho

근본 목적

#67에서 정의한 PK 순수 비교 기준선을 바탕으로, 12B post_id 기준에서 복합 PK가 보조인덱스 개수와 데이터 양에 따라 언제 손익분기점을 넘는지 정량적으로 계산한다. 이번 실험의 목적은 몇 개의 secondary부터, 몇 row부터 단일 PK 전략이 전체 저장비용/밀집도/I/O 측면에서 유리해지는지 수치로 제시하는 것이다.

비목적

이번 이슈는 실제 서비스 전체 스키마를 그대로 재현하거나 feed covering/soft delete 요구사항을 섞어 최종 설계 우열을 단정하기 위한 것이 아니다. 순수 PK 기준선 위에서 break-even을 계산하는 것이 목적이다.

선행 이슈

이번 이슈는 #67의 산출물인 C.PRIMARY, S.PRIMARY, S.uk_post_member, leaf density, 동일 조회 workload I/O를 기반으로 확장 실험을 수행한다.

핵심 질문

  1. 12B post_id 기준에서, 단일 PK 전략은 공통 secondary가 몇 개부터 복합 PK보다 저장비용이 낮아지는가?
  2. 동일한 공통 secondary 개수에서, 데이터 row 수가 몇 개를 넘으면 손익분기점이 생기는가?
  3. 손익분기점 전후에서 rows_per_leaf, buffer_pool_reads/query, data_reads/query는 어떻게 변하는가?
  4. uniformskew 분포는 break-even 지점을 얼마나 이동시키는가?

해석 원칙

이번 실험에서 핵심은 총 인덱스 수를 임의로 다르게 만드는 것이 아니라, 아래 두 비용을 분리해 보는 것이다.

1. S의 고정비

단일 PK 전략은 secondary 개수와 무관하게 항상 아래 두 개를 가진다.

  • PRIMARY(post_like_id)
  • uk_post_member(post_id, member_id)

S는 시작 시점부터 고정 추가 비용을 안고 시작한다.

2. C의 누적비

복합 PK 전략은 공통 secondary가 하나 늘어날 때마다, 그 secondary 엔트리마다 12B post_id + member_id PK가 함께 복제된다.

즉 공통 secondary 개수 N이 커질수록 C는 긴 PK 복제 비용이 누적된다.

3. break-even의 의미

이번 이슈의 break-even은 아래 질문에 답하는 것이다.

  • S의 고정비를 감안해도
  • 공통 secondary N개에 복합 PK가 반복 복제되는 C의 누적비가 더 커지는 지점은 어디인가?

따라서 이번 실험에서 늘리는 것은 공통 secondary 개수이며, CS는 같은 공통 secondary 세트를 가진다. 다만 총 인덱스 수는 구조적으로 다르다.

  • C: PRIMARY(post_id, member_id) + 공통 secondary N
  • S: PRIMARY(post_like_id) + uk_post_member(post_id, member_id) + 공통 secondary N

실험 축

축 A. PK 길이

  • post_id = BINARY(12)로 고정
  • Mongo ObjectId에 가까운 12B 기준선으로 실험

축 B. 공통 secondary 개수

아래 레벨별로 공통 secondary를 점증적으로 추가한다. 모든 레벨에서 CS는 동일한 공통 secondary 세트를 가져야 한다. S는 항상 PRIMARY(post_like_id) + uk_post_member(post_id, member_id)를 별도 고정비로 유지한다.

L0

  • 공통 secondary 없음

L1

  • KEY idx_member (member_id)

L2

  • L1 + KEY idx_created (created_at)

L3

  • L2 + KEY idx_post_created (post_id, created_at)

L4

  • L3 + KEY idx_member_created (member_id, created_at)

L5

  • L4 + KEY idx_created_member (created_at, member_id)

필요 시 L6 이상을 추가하되, post_id 포함 secondary와 member_id 중심 secondary가 섞이도록 구성한다.

축 C. 데이터 양

  • 100,000
  • 300,000
  • 1,000,000
  • 3,000,000 가능 시 추가

축 D. 분포

  • uniform
  • skew

비교 케이스

Case C

CREATE TABLE post_likes_case (
  post_id BINARY(12) NOT NULL,
  member_id BIGINT NOT NULL,
  created_at DATETIME(6) NOT NULL,
  PRIMARY KEY (post_id, member_id),
  ... common secondary for level ...
) ENGINE=InnoDB;

Case S

CREATE TABLE post_likes_case (
  post_like_id BIGINT NOT NULL AUTO_INCREMENT,
  post_id BINARY(12) NOT NULL,
  member_id BIGINT NOT NULL,
  created_at DATETIME(6) NOT NULL,
  PRIMARY KEY (post_like_id),
  UNIQUE KEY uk_post_member (post_id, member_id),
  ... same common secondary for level ...
) ENGINE=InnoDB AUTO_INCREMENT=50000000;

데이터 생성 규칙

  • (post_id, member_id) 유일
  • member_id 시작값 500000
  • post_like_id 시작값 50000000
  • post_id 생성 시드 10000000
  • 각 레벨/스케일/분포 조합에서 두 케이스는 동일 데이터셋을 동일 순서로 적재

측정 항목

1. 총 테이블 크기

  • DATA_LENGTH
  • INDEX_LENGTH
  • total MB

2. 인덱스 상세 크기

  • C.PRIMARY
  • S.PRIMARY
  • S.uk_post_member
  • 각 공통 secondary별 크기
  • common_secondary_total_C
  • common_secondary_total_S
  • secondary_total_all_C
  • secondary_total_all_S

3. 페이지/밀집도

  • size
  • n_leaf_pages
  • rows_per_leaf_page
  • 레벨별 PRIMARY rows/leaf
  • 레벨별 공통 secondary 평균 rows/leaf

4. 단건 조회/반복 조회 I/O

대상 쿼리:

SELECT 1
FROM post_likes_case
WHERE post_id = ?
  AND member_id = ?
LIMIT 1;

측정:

  • EXPLAIN
  • EXPLAIN ANALYZE
  • Innodb_buffer_pool_reads
  • Innodb_data_reads
  • Innodb_pages_written 가능 시 병행
  • query당 reads
  • avg / p95 latency

break-even 계산 방식

1. 고정비와 누적비 분리

각 row count/분포 조합마다 아래 항을 분리 계산한다.

  • S_fixed_cost = S.PRIMARY + S.uk_post_member
  • C_accumulated_cost(N) = C.PRIMARY + common_secondary_total_C(N)
  • S_accumulated_cost(N) = S_fixed_cost + common_secondary_total_S(N)
  • delta_total(N) = S_accumulated_cost(N) - C_accumulated_cost(N)

여기서 N은 공통 secondary 개수다.

2. secondary 개수 기준 손익분기

delta_total(N) <= 0이 되는 최소 공통 secondary 레벨을 secondary-count break-even으로 정의한다.

즉 이 값은:

  • SPRIMARY + uk_post_member라는 고정비를 갖고 시작하지만
  • 공통 secondary가 충분히 많아지면
  • 복합 PK가 반복 복제되는 C의 누적비를 따라잡는 지점이다.

3. row count 기준 손익분기

각 공통 secondary 레벨/분포 조합마다 row 수별 실측치를 가지고 아래를 계산한다.

  • delta_total_mb(row_count)
  • delta_primary_density(row_count)
  • delta_common_secondary_density(row_count)
  • delta_reads_per_query(row_count)

실측 점들 사이 선형 보간 또는 곡선 적합이 가능하면 적용하고, 처음으로 delta_total <= 0 또는 reads_per_query delta <= 0이 되는 row count를 row-count break-even으로 기록한다.

4. 해석 보조 지표

  • S_fixed_cost_mb
  • common secondary 1개 추가당 delta_total 변화량
  • S가 공통 secondary에서 절약한 MB
  • C가 복합 PK 복제로 추가 부담한 MB

기대 산출물

  • break_even_by_secondary.tsv
  • break_even_by_row_count.tsv
  • index_density_matrix.tsv
  • size_matrix.tsv
  • io_matrix.tsv
  • 최종 해석 보고서

성공 기준

  • 12B post_id 기준 손익분기 공통 secondary 개수를 표로 제시할 수 있어야 한다.
  • 공통 secondary 레벨별 손익분기 row count를 표로 제시할 수 있어야 한다.
  • 각 분기점에서 S 고정비C 누적비가 분리된 표로 설명돼야 한다.
  • 저장 크기 결과와 조회 I/O 결과가 분리된 형태로 해석 가능해야 한다.

TODO

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions