MongoDB University, M201 코스 정리
in Study
M201 코스 정리 (1)
Lesson 2.1 Introduction to Indexes
What are Indexes?
우리는 인덱스를 통해 어떤 것을 해결할 수 있을까요?
슬로우 쿼리 입니다.
데이터 베이스의 인덱스는 마치 책의 목차와 근본적으로 동일합니다. 여기서 책은 Collection에 해당합니다. 만약 컬렉션에 인덱스를 사용하지 않으면 데이터베이스는 특정 document를 찾기위해 전체를 훑어봐야 합니다. 이러한 경우를 Collection Scan이라 부릅니다. Collection의 크기가 커질수록 선형적으로 검색 속도가 증가합니다. MonboDB의 인덱스는 B-tree구조로 되어 있습니다. 따라서 Collection의 크기가 증가해도 인덱스를 사용하면 필요한 document를 찾기위해 비교하는 횟수는 log(N)의 복잡도를 가집니다.
Index OverHead
인덱스를 사용하면 Read를 할 때 엄청난 퍼포먼스를 보여주지만 그에 대한 댓가가 따릅니다. 그것은 인덱스가 추가되면 될 수록 Write하는데 시간이 더 걸리게 되는 것입니다. 새로운 Document가 추가될 때 마다 Collection과 Index가 업데이트 되어야 하기 때문입니다. Document가 수정되거나 완전히 제거될 때도 마찬가지로 B-tree가 업데이트 되어야 합니다. 따라서 중요하지 않은 키에 인덱스를 걸게되면 insert, update, delete를 하는 경우에 불필요한 퍼포먼스 저하가 일어나게 됩니다. 따라서 인덱스에도 무조건 적인 장점만 있는 것이 아니기 때문에 어떻게 동작하는지, 인덱스의 장점과 단점은 무엇인지를 명확하게 알아야합니다.
How do they work?
데이터베이스는 데이터를 영구히 저장하기 위해 서버의 파일시스템을 사용합니다. 그렇다면 데이터베이스가 어떤 파일에 어떤 정보를 기록하게 될까요? 데이터베이스가 어떤 자료구조와 스토리지 엔진을 사용하여 Collection과 Index를 구성하고 데이터를 영구히 기록하게 될까요?
How Data Is Stored on Disk
Data Management Object - Collection Data / Index
MongoDB에서 데이터를 저장하는 방식은 MongoDB가 지원하는 스토리지 엔진마다 차이가 있습니다만 여기에선 그런 디테일을 건너뛰고 좀 더 거시적인 수준에서 스토리지 엔진이 어떻게 데이터를 구성하는지 알아보겠습니다. WiredTiger에서는 3가지 방식이 있다 Plain Flat - 하나의 경로에서 collection, index DirectoryPerDB - 디비마다 경로가 생기고 collection, index WiredTigerIndexPerDB - 디비마다 경로가 생기고 collection / index 별로 구분 됨
서버에 여러개의 디스크가 있는 경우 I/O 병렬화가 사용되엉 퍼포먼스 향상, 전체적인 처리량 향상
Data Compression
Disk에 데이터를 저장할 때 압축을 하게 되는데 이것은 더욱 적은 I/O 오퍼레이션을 요구하므로 더욱 성능향상에 직접적인 연관을 줍니다. 데이터가 디스크에 써지기 전에 먼저 RAM에 올라가게 되고 그 이후에 디스크에 써지는데 이 경우에 writeConcern 설정을 이용하여 메모리에서 디스크에 쓰일 때 어떤 정책을 선택할 것인지 유저사이드에서 결정할 수 있으며 그 외에는 내부에서 메모리와 디스크의 싱크를 맞추는 주기에 따라 메모리에서 디스크로 쓰이고 flush가 됩니다. 저널 또한 중요한 메커니즘 중 하나로서 저널파일은 완전히 저장되지 않은 파일에 대한 안전망입니다 시스템ㅇ이 갑자기 꺼져서 데이터가 file로 쓰여지지 않은 경우 저널 파일에서 이를 복구하게 됩니다. 파일을 insert할 때도 저널과 동기화를 거쳐서 disk에 쓰도록 설정이 가능합니다 다만 이런 것들은 모두 어플리케이션 관점에서 볼 때 퍼포먼스에 영향을 주는 것입니디다. 레플리카 셋 중 몇에게 메모리의 데이터를 쓸 것인지, 메모리의 데이터에서 디스크로 쓸 때 저널과 얼마나 동기화를 맞출 지 하는 설정인 것입니다.
Single Field Indexes
Understanding Explain
UnderStanding Explain Sharded Clusters
Compound Indexes
Index Prefixes
Sort With Index
MultiKey Indexes
- 인덱스를 건 필드가 배열인 경우 이것을 멀티키 인덱스라 부른다
- 배열에 들어있는 엔트리마다 서버는 분리된 인덱스를 만든다.
- a 배열과 b 배열에 인덱스를 거는경우 해당 인덱스의 길이는 a.length * b.length 다.
- 이 경우 인덱스의 크기가 매우 커지기 때문에 퍼포먼스에 영향을 준다.
- 따라서 몽고디비는 인덱스를 걸 때 오직 1개의 배열 필드만 가능하다.
- 멀티키 인덱스는 covered 쿼리를 지원하지 않는다.
- 필드에 인덱스를 걸어도 도큐먼트를 추가할 때 해당 필드가 배열이 아니면 인덱스를 만들지 않는다.
- 컴파운드 인덱스를 걸 때는 1개의 필드만 배열이 가능하다.
- 인덱스를 건 이후에 컴파운드 인덱스 걸린 필드 중 배열이 2개 이상이 되면 에러가 난다.
Partial Indexes
- 특정 필드의 조건을 걸어서 만족할 때만 인덱스를 건다.
- 인덱스의 크기를 줄이므로 퍼포먼스에 도움이 된다.
- 부분 인덱스를 사용하는 경우 쿼리에도 해당 필터값이 들어가있어야 인덱스를 탄다.
Text Indexes
- MongoDb에서는 멀티키 인덱스 처럼 하나의 text에 word 별로 인덱스를 만든다 ( lowerCase default )
- 인덱스가 많은 경우 발생하는 것
더 많은 키 비교, 인덱스 사이즈 증가 인덱스 구성 시간 증가 Write 퍼포먼스 감소
- 따라서 컴파운드 인덱스를 구성하면 더욱 적은 인덱스가 생성된다.
- text 검색 시에는 단어별 or 검색이 된다.
Collations
- locale 별 인덱스를 달리 적용 가능,
- 상황별로 유연하게 인덱스를 적용 가능
Wildcard Indexes
- 접근 패턴이 명확하지 않은 쿼리에 대해 사용가능
- 컬렉션의 모든 필드에 인덱스를 걸 수 잇다
- 임베딩된 필드에 대하여 wildcard projection을 통해 임의적으로 구분하여 인덱싱 가능
- 기존의 인덱스를 대체할 수 없다.
Wildcard Use case
- 쿼리패턴을 정확하게 모르는 경우
- attribute pattern 을 사용하는 경우
Hybrid Index Build (4.2 feature)
AS-IS ( 2가지 인덱스 생성방식 )
- foreground index build
인덱스를 생성하는 동안 데이터베이스 전체에 락을 ( read / write 불가 )
- background index build
데이터베이스에 락을 걸지 않아서 read/write 가 가능하지만 속도가 느림 ( 주기적으로 데이터베이스에 락을 건다 )
4.2부터는 하이브리드 매커니즘으로 foreGround/backGround의 좋은 점만 취했다. (lockless, performant )
Query Plan
Waht is Query Plan?
이미지
Query Optimizer
이미지 canditdate Indexes, Query Planner가 각 플랜별 실행시간을 따져보고 가장 퍼포먼스가 좋은 것을 선택함 선택받은 Plan은 winning plan, 그렇지 않은 Plan은 rejected plan이 됨
cache
이미지 위의 쿼리 플래너가 어떤 플랜을 선택했는지가 캐싱되고 해당 형태의 쿼리가 들어오면 바로 캐싱되어 있는 winning plan을 선택 따라서 서버 재시작, 인덱스 생성/드랍이 되는 경우 캐시가 날아감
Hint
hint()메소드를 사용하여 MongoDB의 기본 인덱스 선택을 오버라이딩 쿼리 옵티마이저가 항상 우리가 바라는 대로 인덱스를 선택하는 것이 아니다 이미지 일반적으로 쿼리 옵티마이저는 꽤 괜찮게 올바른 인덱스를 선택한. 쿼리 옵티마이저가 올바른 선택을 못하는 이유는 컬렉션에 많은 인덱스가 있는 경우다. 이런 경우에는 힌트를 사용하는 것보다는 많은 인덱스를 한번 정리하는게 낫다.
Resource Allocation for Indexes
쿼리 최적화, 응답시간 감소에 도움이 된다. 인덱스는 퍼포먼스에 아주 큰 요소이지만 그만큼 자원을 소비한다. 따라서 인덱스의 크기를 결정하는 것, 인덱스 크기에 따라 연관된 자원들을 아는 것이 중요하다. 인덱스는 2가지 컴퓨팅 자원이 필요하다 ( 디스크, 메모리 ) 사실 디스크는 크게 중요하지 않다. 인덱스가 생성하고 그것을 저장할 공간만 있으면 된다. 메모리가 중요한데, 인덱스가 한번에 메모리에 올라가지 않으면 디스크를 활용하여 페이징 처리 하게 된다. 인덱스가 hit하지 않으면 다시 디스크에서 인덱스를 읽어 메모리에 올리는 과정이 필요하 (page in - page out)에 시간이 많이 소비됨 인덱스의 어떤 부분이 올라가있는지 확인하는 방법 - 이미지