포스트

2021-05-26-TIL

2021-05-26-TIL

Subquery vs Join

같은 결과를 서브쿼리로도, 조인으로도 쓸 수 있을 때 어느 쪽이 나은지는 옵티마이저에 달려 있다. 오래된 MySQL에서는 WHERE id IN (SELECT ...) 형태의 서브쿼리가 바깥 행마다 반복 실행되는 식으로 처리되어 느린 경우가 많았고, 그래서 조인으로 바꾸라는 조언이 널리 퍼졌다. 링크된 글은 MySQL 5.5와 5.6에서 WHERE IN (서브쿼리)와 조인의 성능을 비교한다. 5.5에서는 옵티마이저가 서브쿼리를 상관 서브쿼리 형태로 바꿔 실행해 느렸고, 5.6에서 서브쿼리 최적화가 크게 개선되었다는 내용이다. 이후 버전의 옵티마이저는 이런 서브쿼리를 세미 조인 등으로 변환해 처리한다. 결국 규칙을 외우기보다 EXPLAIN으로 실제 실행 계획을 확인하는 것이 확실하다.

  • https://jojoldu.tistory.com/520

MySQL Storage Engine

MySQL은 테이블마다 저장 엔진을 고를 수 있다. MySQL 8.0의 기본 엔진은 InnoDB로, 트랜잭션(ACID), 행 단위 잠금, 외래 키, 장애 복구를 지원한다. MyISAM은 MySQL 문서의 설명대로 크기가 작지만 테이블 단위 잠금이라 읽기와 쓰기가 섞인 부하에서 성능이 제한되고, 주로 읽기 위주 작업에 쓰였다. Memory 엔진은 모든 데이터를 RAM에 둔다. 일반적인 서비스 테이블이라면 InnoDB를 쓰면 된다.

  • https://dev-ahn.tistory.com/72

Row Store vs Column Store

행 저장소는 한 행의 모든 컬럼을 디스크에 연속으로 저장하고, 열 저장소는 한 컬럼의 값들을 연속으로 저장한다. 그래서 행 저장소는 한 행 전체를 읽고 쓰는 OLTP(주문 한 건 조회, 수정)에 유리하고, 열 저장소는 많은 행에서 일부 컬럼만 집계하는 분석 쿼리(OLAP)에 유리하다. 필요한 컬럼만 읽으면 되고, 같은 타입의 값이 모여 있어 압축률도 높기 때문이다. Microsoft 문서는 columnstore 인덱스를 대용량 데이터 웨어하우스 팩트 테이블을 저장하고 조회하는 표준으로 소개한다. 대신 열 저장소는 한 행을 넣거나 바꿀 때 여러 컬럼 영역을 건드려야 해서 단건 쓰기가 느리다.

  • https://www.percona.com/blog/2016/12/14/row-store-and-column-store-databases/#:~:text=At%20a%20basic%20level%2C%20row,for%20a%20subset%20of%20columns.
  • https://docs.microsoft.com/en-us/sql/relational-databases/indexes/columnstore-indexes-overview?view=sql-server-ver15#:~:text=Columnstore%20indexes%20are%20the%20standard,over%20traditional%20row%2Doriented%20storage.
  • https://www.emoreau.com/PrintThisPage.aspx?ID=568

SSD page and block

NAND 플래시 SSD는 읽기와 쓰기를 페이지 단위로 하지만, 지우기는 여러 페이지를 묶은 블록 단위로만 할 수 있다. 또 이미 쓴 페이지를 제자리에서 덮어쓸 수 없다. 그래서 데이터를 수정하면 SSD 컨트롤러(FTL, Flash Translation Layer)는 새 내용을 빈 페이지에 쓰고 예전 페이지를 무효로 표시한다. 무효 페이지가 쌓이면 가비지 컬렉션이 블록의 유효 페이지를 다른 곳으로 옮긴 뒤 블록을 지운다. 이 과정에서 실제 쓰기량이 요청보다 커지는 쓰기 증폭이 생긴다. 링크된 카카오 기술 블로그의 “Coding for SSD” 연재가 이 구조와 그에 맞는 프로그래밍 방법을 설명한다.

  • https://tech.kakao.com/2016/07/18/coding-for-ssd-part-6/#:~:text=NAND%20%ED%94%8C%EB%9E%98%EC%8B%9C%20%EB%B8%94%EB%A1%9D%EA%B3%BC%20%ED%8E%98%EC%9D%B4%EC%A7%80&text=%EB%98%90%ED%95%9C%20%EB%8C%80%EB%B6%80%EB%B6%84%EC%9D%98%20SSD%EC%97%90%EC%84%9C%EB%8A%94,%EC%82%AC%EC%9D%B4%EC%A6%88%EB%A5%BC%20%EA%B0%80%EC%A7%80%EA%B2%8C%20%EB%90%98%EB%8A%94%20%EA%B2%83%EC%9D%B4%EB%8B%A4.

Index in DB

인덱스는 특정 컬럼 값으로 행을 빨리 찾기 위해 정렬된 별도 자료구조를 두는 것이다. 책의 찾아보기처럼 전체를 훑지 않고 원하는 위치로 바로 간다. 대신 데이터가 바뀔 때마다 인덱스도 갱신해야 해서 쓰기 비용과 저장 공간이 늘어난다. 그래서 조회 조건에 자주 쓰이고 값의 종류가 많은(선택도가 높은) 컬럼에 거는 것이 효과적이다. 링크된 글의 요약처럼 대용량 테이블에서 소량의 행을 찾을 때 인덱스가 의미 있고, 테이블의 많은 부분을 읽는 쿼리에서는 오히려 전체 스캔이 나을 수 있다.

  • http://wiki.gurubee.net/pages/viewpage.action?pageId=29065492#:~:text=%EC%9D%B8%EB%8D%B1%EC%8A%A4%EB%8A%94%20%EB%8C%80%EC%9A%A9%EB%9F%89%20%ED%85%8C%EC%9D%B4%EB%B8%94%EC%97%90%EC%84%9C,%EC%8A%A4%EC%BA%94%EC%9D%B4%20%EC%9D%98%EB%AF%B8%ED%95%98%EB%8A%94%20%EB%B0%94%EC%9D%B4%EB%8B%A4.
  • https://beelee.tistory.com/37

Clustering Index

클러스터드 인덱스는 인덱스 순서대로 실제 행 데이터를 저장하는 인덱스라 테이블당 하나뿐이다. MySQL 문서에 따르면 InnoDB 테이블은 행 데이터를 저장하는 클러스터드 인덱스를 하나씩 가지며, 보통 기본 키가 클러스터드 인덱스다. 나머지 보조 인덱스(secondary index)는 행 위치 대신 기본 키 값을 담고 있어서, 보조 인덱스로 찾은 뒤 기본 키로 클러스터드 인덱스를 한 번 더 탐색한다. 기본 키가 크면 모든 보조 인덱스도 커지므로 기본 키는 짧게 잡는 편이 좋다.

  • https://mongyang.tistory.com/75

B-tree and B+tree

B-tree는 노드 하나에 여러 키를 담는 균형 탐색 트리로, 트리 높이가 낮아 디스크 접근 횟수가 적다. B+tree는 그 변형으로, 실제 데이터(또는 행 포인터)는 리프 노드에만 두고 내부 노드에는 탐색용 키만 둔다. 내부 노드에 키를 더 많이 담을 수 있어 트리가 더 낮아지고, 리프 노드끼리 연결 리스트로 이어져 있어 범위 조회(BETWEEN, ORDER BY)를 리프를 따라가며 순차적으로 처리할 수 있다. 대부분의 RDBMS 인덱스가 B+tree 계열을 쓰는 이유다.

  • https://www.geeksforgeeks.org/difference-between-b-tree-and-b-tree/
  • https://www.javatpoint.com/b-tree-vs-bplus-tree
  • https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Tree

LBA

LBA(Logical Block Addressing)는 저장 장치의 블록을 0부터 시작하는 하나의 일련번호로 가리키는 주소 방식이다. 예전의 CHS(실린더, 헤드, 섹터) 방식처럼 디스크의 물리 구조를 알 필요 없이 번호만으로 접근한다. SSD에서는 FTL이 이 논리 주소를 실제 플래시 페이지 위치로 바꿔 준다. 위의 덮어쓰기 불가 문제를 운영체제가 몰라도 되는 이유다.

  • https://en.wikipedia.org/wiki/Logical_block_addressing
참고한 자료외부 출처 4

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다