inflearn logo
Course

Course

Instructor

yh's Posts

yh yh

@yh

Students
609,862
Reviews
42,655
Course Rating
5.0

Posts 9129

Q&A

탐색을 한번 더 하지 않게 하는 방식 중 어댑티브 해시 방식도 맞는지 궁금 합니다.

안녕하세요. ggg7515님 어댑티브 해시 인덱스(AHI)도 탐색을 줄이는 건 맞지만, 절약하는 비용의 종류가 커버링 인덱스와 다릅니다. 커버링 인덱스는 세컨더리 인덱스 → 클러스터링 인덱스로 가는 추가 탐색 자체를 없앱니다. 접근할 페이지 수가 줄어들기 때문에, 해당 페이지가 버퍼 풀에 없다면 디스크 I/O까지 실제로 줄어듭니다. 반면 AHI는 버퍼 풀에 이미 올라와 있는 페이지에 대해서만 동작합니다. 자주 조회되는 키 값 → 버퍼 풀 내 레코드 위치를 해시로 매핑해두고, 루트 → 브랜치 → 리프로 내려가는 B+Tree 탐색을 건너뛰게 해줍니다. 즉 절약되는 건 메모리 안에서의 트리 탐색 비용(CPU)이지 디스크 I/O가 아닙니다. 페이지가 버퍼 풀에 없으면 어차피 디스크에서 읽어야 하고, 이 경우 AHI는 도움이 되지 않습니다. 정리하면 커버링 인덱스는 I/O 최적화, AHI는 CPU 최적화입니다. 그리고 한 가지 중요한 점은, MySQL 8.4부터 AHI가 기본 비활성화로 바뀌었다는 것입니다. 현대 워크로드에서는 이점보다 경합, 유지 비용이 더 큰 경우가 많다는 판단이 반영된 변경입니다. 감사합니다.

Likes
0
Comments
2
Viewcount
32

Q&A

PK 관련하여 궁금한 점이 있어서 질문 드립니다.

Gomgomi님 다음 강의에서 필요한 내용을 얻으셨군요 ㅎㅎ 아마도 궁금해하실 것 같아서 복선을 깔아두었는데, 거기 걸리셨습니다 ㅎㅎㅎ 감사합니다.

Likes
0
Comments
2
Viewcount
33

Q&A

통계정보 갱신 질문

안녕하세요. backendman님 결론부터 말하면 MySQL 8.0.24 기준으로 트레이드오프는 거의 없습니다. InnoDB의 ANALYZE TABLE 은 테이블 전체를 스캔하는 게 아니라 인덱스별로 일부 페이지만 샘플링합니다(기본 20페이지). 그래서 수억 건 테이블도 보통 수 초 안에 끝나고 부하도 미미합니다. 실무에서는 문제가 반복되는 테이블에 새벽 배치로 ANALYZE TABLE 을 정기 실행하는 게 흔한 패턴입니다. 자동 재계산이 "행의 10% 변경" 시점에만 동작해서 대용량 테이블은 통계가 낡기 쉽기 때문입니다. USE INDEX 는 즉효약이지만 플랜을 고정시켜서 데이터 분포가 바뀌어도 옛 플랜을 강제하는 유지보수 리스크가 있습니다. 통계 갱신으로 옵티마이저가 스스로 올바른 판단을 하게 만드는 게 근본 해결이고, 힌트는 그래도 안 되는 특수 케이스에만 남기는 걸 권장합니다. 감사합니다.

Likes
0
Comments
2
Viewcount
42

Q&A

컬럼 크기가 대용량인 경우 DB 버퍼 풀에 전부 올라오는지 궁금합니다

안녕하세요. ggg7515님 결론부터 말씀드리면, 해당 컬럼 값 전체가 버퍼 풀을 거쳐서 올라옵니다. InnoDB는 데이터를 항상 페이지(기본 16KB) 단위로 읽고 씁니다. 그런데 1MB 정도의 큰 컬럼 값은 하나의 페이지에 담을 수 없기 때문에, InnoDB는 이런 값을 별도의 외부 페이지(overflow page)에 나누어 저장하고, 원래 레코드에는 그 위치를 가리키는 포인터만 남겨둡니다. 따라서 이 컬럼을 조회하면 InnoDB는 포인터를 따라가며 1MB를 담고 있는 약 64개의 외부 페이지를 모두 읽어야 하는데, InnoDB의 모든 페이지 읽기는 반드시 버퍼 풀을 통해서만 일어납니다. 대용량 값이라고 해서 버퍼 풀을 우회하는 별도 경로는 없습니다. 값 전체가 버퍼 풀에 올라온 뒤에 MySQL 서버가 이를 조합해서 클라이언트로 전송합니다. 두 번째 질문도 중요한 포인트인데요, 애플리케이션에서의 스트림 처리는 결과를 행 단위로 받아서 애플리케이션 서버의 메모리를 아끼는 기술입니다. 하지만 DB 입장에서는 어차피 각 행을 만들기 위해 해당 컬럼 전체를 버퍼 풀에 읽어야 하므로, 클라이언트가 스트림으로 받는다고 해서 DB의 메모리 사용이 줄어들지는 않습니다. 오히려 스트림 방식은 커넥션을 더 오래 점유하는 비용도 있습니다. 추가로 실무 관점을 말씀드리면, 이런 대용량 컬럼은 버퍼 풀을 빠르게 채워서 정작 자주 쓰는 인덱스와 데이터 페이지를 밀어낼 수 있습니다. 그래서 실무에서는 보통 다음과 같이 설계합니다. 첫째, 대용량 컬럼은 꼭 필요한 경우에만 SELECT 합니다(SELECT *를 피하고 컬럼을 명시). 둘째, 일부만 필요하면 SUBSTRING으로 나누어 읽는 방법도 있습니다. 셋째, 1MB급 데이터라면 파일 스토리지(S3 등)에 저장하고 DB에는 메타데이터와 경로만 보관하는 설계를 가장 많이 사용합니다. 감사합니다.

Likes
0
Comments
2
Viewcount
31

Q&A

MySQL 서버구조 쿼리파서 질문 있습니다 !

안녕하세요. ggg7515님 개념적으로는 두 단계로 나누어 이해하시면 됩니다. 먼저 어휘 분석(Lexical Analysis) 에서 SQL 문장을 SELECT , FROM , 테이블명과 같은 토큰으로 분리 합니다. 그다음 구문 분석(Syntax Analysis) 에서 토큰의 순서가 SQL 문법에 맞는지 검증하고, 이후 처리에 사용할 파스 트리(Parse Tree) 를 만듭니다. 따라서 하나의 쿼리 파싱 과정 안에서 연속적으로 수행되지만, 역할은 서로 다른 단계입니다. 일반적으로는 이 두 과정을 합쳐서 넓은 의미의 쿼리 파싱 이라고 표현합니다. 감사합니다.

Likes
0
Comments
1
Viewcount
46

Q&A

Postgresql 아키텍처 업데이트

안녕하세요. yp kim님 강의를 재미있게 들어주셔서 감사합니다 :) PostgreSQL 아키텍처 강의는 아쉽지만 계획하고 있지 않습니다. 다만 지금 배우고 계신 데이터베이스의 핵심 원리는 PostgreSQL에도 많은 부분이 적용되는 내용입니다. 강의를 끝까지 들으신 다음 PostgreSQL 문서를 보시면, 공통점과 차이점이 훨씬 선명하게 보이실 것입니다. 남은 강의도 재미있게 들어주세요. 감사합니다.

Likes
1
Comments
2
Viewcount
61

Q&A

실습데이터 ORDERS 생성 시간 질문요...

안녕하세요. leelojhol님 뭔가 문제가 있는 것 같습니다! 데이터베이스를 삭제하고 용량을 확보한 다음에 다시 시도해주세요! 감사합니다.

Likes
0
Comments
1
Viewcount
57

Q&A

조인의 특징

재앙님 좋은 피드백이네요^^! 메뉴얼에 참고사항으로 반영해두겠습니다^^! 고맙습니다.

Likes
0
Comments
2
Viewcount
21

Q&A

상태 기반 데이터관리에서 특정 시점에 대한 정보는 어떻게 관리할 수 있나요?

안녕하세요. yeoeol님 상태 컬럼과 함께 deleted_at을 두는 것이 좋지 않은 이유는 "삭제(탈퇴) 여부"라는 같은 사실을 status와 deleted_at 두 곳에서 중복 관리하게 되기 때문입니다. status는 WITHDRAWN인데 deleted_at은 NULL인 것처럼 두 정보가 어긋나면 데이터 정합성이 깨집니다. 시점 정보 자체가 나쁘다는 뜻은 아닙니다. 그래서 실무에서는 보통 이렇게 접근합니다. 1. 현재 상태의 변경 시점만 필요하다면: status + status_changed_at 하나면 충분합니다. 상태가 바뀔 때마다 함께 갱신하면 "언제 탈퇴했는지"는 status=WITHDRAWN + status_changed_at으로 알 수 있습니다. 상태별로 suspended_at, banned_at, withdrawn_at을 각각 두면 컬럼이 계속 늘어나고 관리가 어려워집니다. 2. 모든 상태 변경 이력이 필요하다면(정지 → 해제 → 재정지 같은 흐름): 이력 테이블이 정답입니다. 그런데 생각보다 거창하지 않습니다. user_status_history(id, user_id, status, changed_at, reason) 정도의 테이블 하나에 상태 변경 시 INSERT만 추가하면 끝이라, 개인 프로젝트에서도 충분히 사용할 수 있는 수준입니다. 에이전트의 답변처럼 탈퇴 시점이 업무적으로 특히 중요한 경우 withdrawn_at을 별도로 두는 것도 실무에서 흔히 쓰는 합리적인 선택입니다. 다만 이때는 상태 변경과 시점 기록이 항상 함께 이루어지도록 한 곳(서비스 로직)에서 묶어서 처리해야 정합성이 유지됩니다. 정리하면, 개인 프로젝트라면 status + status_changed_at으로 시작하고, "이력 추적"이라는 요구사항이 생기는 시점에 이력 테이블을 도입하면 됩니다. 설계에 하나의 정답이 있는 것이 아니라, 요구사항에 맞는 트레이드오프를 선택하는 것이 핵심입니다. 감사합니다.

Likes
0
Comments
1
Viewcount
24

Q&A

run() 메서드 안에 지역변수 sum을 사용한 이유

안녕하세요. ᄒᄉ님 제가 이렇게 작성한 이유는 공유 자원에 대한 접근을 최소화한다는 원칙 때문입니다. result는 멤버 변수, 즉 다른 스레드에서 접근 가능한 공유 자원입니다. result += i로 작성하면 계산이 진행되는 동안 result에는 1, 3, 6, 10... 같은 불완전한 중간 상태가 계속 노출됩니다. 이 시점에 다른 스레드가 result를 읽으면 의미 없는 값을 보게 되죠. 반면 지역 변수로 계산을 끝내고 마지막에 result = sum 한 번만 대입하면, result는 0 아니면 1275(완성된 값) 두 가지 상태만 가집니다. 중간 상태가 존재하지 않는 것이 핵심입니다. 계산은 스레드 내부(스택)에서 안전하게 끝내고, 공유 자원에는 완성된 결과만 딱 한 번 넘기기 위해서 이렇게 작성한 것입니다. 감사합니다.

Likes
0
Comments
1
Viewcount
71