4단계: 쿼리 모델링 및 데이터 변환
대부분의 내용이 넓은 주제를 짧게 설명하는 내용이라 알게 된 내용 중 몰랐던 부분에 대해서 간략하게 적겠습니다.
쿼리 모델링
효율적인 쿼리를 작성하는 건 기본적이지만 가장 중요한 역량이라고 생각합니다. 개인적으로 노력하고 있지만, 다시한번 짚어주는 내용에 대해서는 적을 필요가 있다고 생각하여 기록합니다.
1. 조인 전략 및 스키마 최적화
첫 번째로 선조인을 하는 것이 기본적으로 효율적인 조인 전략이라고 합니다. 분석 쿼리가 동일한 데이터를 반복하여 조인 할 경우 계산 부하가 높은 작업을 반복하지 않도록 데이터를 조인하고 선 조인 된 데이터 버전에서 쿼리하는 것이 좋다고 합니다. 단 개인적으로 사용했던 임팔라 등의 분산 환경에서는 조금 다를 수 있습니다. 이 내용은 포스트에서 맵 사이드 조인을 참고하면 좋습니다.
2. Explain을 활용
Explain에서 다음과 같은 내용을 파악하면 좋다고 합니다.
- 디스크, 메모리, 네트워크 등의 주요 리소스 사용량
- 데이터 로딩 시간과 처리 시간 비교
- 쿼리 실행 시간, 레코드 수, 스캠한 데이터의 크기, 데이터 셔플링에 사용된 데이터양
- 데이터베이스에서 리소스 경합을 일으킬 수 있는 경쟁 쿼리
- 사용 가능한 연결 수 대비 사용된 동시 연결 수
3. 전체 데이터 스캔 방지
데이터베이스에서는 인덱스를 사용합니다. 그리고 대부분의 분산 환경에서의 쿼리는 인덱스 및 파티션의 사용을 필수로 해야 합니다.
4. 데이터베이스 마다의 트랜잭션을 확인합니다.
기본적으로는 ACID의 강도를 확인 할 필요가 있습니다. 이 부분은 상당히 중요하기 때문에 추가적으로 남기겠습니다.
RDB의 경우에는 대체로 강력한 ACID를 지원합니다. 즉 변동사항이 생기면 트랜잭션 단위로 커밋하고 즉시 반영되기 때문에 쓰기 작업에서 안정성을 보장하지만 그만큼 느립니다.
MongoDB와 같은 NoSQL은 매우 높은 쓰기 성능을 지원하지만 과부화가 발생하면 무의식적으로 쓰기를 폐기시켜 버립니다. 트랜잭션도 일부 유연하게 지원하기 때문에 신경써야 합니다.
분산환경에서는 더 심각합니다. 애초에 여러 노드가 동일한 데이터를 바라보는 시점이 다릅니다. 최종적으로는 동일한 데이터를 가질 수 있지만, 리더의 유무와 그 수의 차이로 인해서 데이터를 동기화하고 커밋이 실행되기 때문에 이 점을 고려해야 합니다.
5. Vacuum
이 부분은 이번에 알게 된 내용 중 좋은 내용입니다.
데이터베이스에 새로운 데이터를 쓰면 기록 한 후 그 지점으로 포인터를 옮겨서 최신 데이터를 유지합니다. 그리고 이전 데이터를 남아있게 되는데, 이 경우 Vacuum dead record라고 불리는 이전 데이터가 스토리지 공간을 차지하고 심지어는 쿼리 계획에도 포함되게 되어 성능에 안좋은 영향을 준다고 합니다.
Vacuuming을 통해 이러한 이전 데이터를 지속적으로 삭제해주어야 한다고 합니다.
6. 캐시된 쿼리 결과 활용
대부분의 클라우드 OLAP 데이터베이스가 쿼리 결과를 캐시합니다. redshift에서 이 내용을 한번 확인 할 필요가 있을 것 같습니다.
아니면 사용자 환경을 개선하기 위해 구체화 뷰를 하나 구축하면 좋다고 합니다.
스트리밍 데이터의 쿼리
패스트 팔로워
패스트 팔로워라는 단어가 조금 생소한데, 운영 데이터베이스에 쿼리 부담이 가지 않도록 분석 데이터베이스를 별도로 구축하고 CDC를 통해 팔로워로써 동작시키는 방식입니다.
너무 한정적으로 말하지만 빅쿼리의 경우에도 카파 아키텍처와 유사한 스트리밍 버퍼 방식을 활용하는 것 같습니다.
카파 아키텍처
대략적으로 알고있는 내용에서 추가적으로 알아보기 위해 적습니다.
카파 아키텍처는 스트리밍 스토리지 시스템을 버퍼로 취급하여 긴 보존 기간동안 이벤트를 보관하며, 그 내용을 직접 쿼리하는 방식으로 동작하는 아키텍처입니다. 이 경우 오랜 기간을 보관하기 위해 일반적으로 사용하는 스토리지를 없애고 이 기능까지 동시에 수행 할 수 있는 하나의 스트리밍 스토리지 시스템을 가지는 것과 동일합니다.
카프카 KSQL은 집계, 통계 계산 및 세션화까지 지원하며 다른 외부 도구에서 카프카 내 데이터 범위를 가지고 쿼리 할 수 있습니다.
윈도
윈도 자체는 스트리밍 쿼리 및 처리에서 필수적인 기능으로 동적 트리거를 기반으로 처리되는 작은 배치라고 합니다.
- 세션윈도
- 근접하게 발생한 이벤트를 그룹화하고 이벤트가 발생하지 않으면 필터링하는 윈도입니다.
- 세션 정보를 알 수 있으므로 후속 전략을 세울 수 있습니다.
- 고정 시간/ 슬라이딩 윈도
- 포스트를 참고해주세요
- 워터마크와 트리거
- 좋은 포스트를 발견해서 저장합니다
- 워터마크는 얼마나 지연 된 데이터까지 반영 할 것인가에 대한 임계지점 정도로 이해했습니다.
- 트리거는 어느 시점에 데이터를 넘겨 줄 것인가에 대한 전략으로 이해했습니다.
- 보강
- 스트림과 객체 스토리지등의 데이터 스토리지와 합쳐 완성도 있는 하나의 데이터 셋을 만드는 것입니다.
- 스트림 간 조인
- 윈도 단위로 쪼개어진 상태에서 스트림간의 조인을 할 수 있습니다.
- 이벤트나 상태 단위로 나누어진 스트림의 경우 원하는 정보를 얻기위해 사용하는 것 같습니다.
배치 분석 데이터 모델링 기술
- 인먼
- 일반적인 데이터 웨어하우스 방식입니다.
- 원천 시스템에서 데이터 웨어하우스로 불러와 데이터 마트를 구성하여 리포팅하는 과정을 말합니다.
- 킴벌
- 이벤트 자체를 저장하는 팩트 테이블을 하나 두고 조인하여 정보를 종합 할 수 있는 차원 테이블을 별도로 두어 필요시 조인하여 데이터를 조회하는 방식입니다.
- 스타 스키마
- 필요한 차원으로 둘러싸인 팩트 테이블입니다.
- 비즈니스 단위마다 별도의 스타 스키마가 존재하고, 분류되어 있기 때문에 조인이나 성능이 효율적입니다.
- 데이터 볼트
넓은 비정규화 테이블
이 부분에서도 정리 할 부분이 있었습니다. 과거에 임팔라 테이블에 관련해서 고민하던 부분이 있었고, 컬럼형 데이터베이스에 대해 공부를 했지만, 명확하게 말하기 꺼려하는 부분이 있었기에 확신을 갖지 못했던 부분입니다.
컬럼형 데이터베이스의 경우에는 NULL은 거의 공간을 차지하지 않습니다. 관련 내용을 Clickhouse 관련 논문에서 본 적이 있는데, (물론 논문은 항상 최상의 결과만을 적지만) NULL값이 0.65bit 만을 차지하도록 압축된다는 문장을 봤습니다. 또한 읽기 속도에 영향을 거의 미치지 않기 때문에 컬럼기반 데이터베이스의 경우에는 와이드 테이블도 고려 할 필요가 있다고 합니다.
와이드 테이블은 스트리밍 데이터에도 적합하다고 합니다.
변환
조인 ( 브로드캐스트, 셔플 해시 등 )
브로드캐스트 조인은 상대적으로 작은 테이블을 미리 연산을 수행하는 노드의 메모리에 올리고 난 후 대상이 되는 테이블을 분산하여 불러온 후 조인하는 방식입니다.
셔플 해시 조인은 브로드캐스트 조인의 단점 중 하나인 “하나의 테이블을 각 노드가 통째로 가지고 있는 문제”를 해결하기 위해서 각 노드에 양쪽 테이블의 내용을 분할하여 조인을 하는 방식입니다. 사용하는 메모리 공간 등은 줄어들지만 부하는 커집니다.
갱신 패턴
입력 전용
입력 전용은 이전 레코드를 변경하거나 삭제하지 않고 새 레코드만 삽입합니다. 행 기반 데이터베이스의 경우에는 기본키를 가지고 특정 행을 고정하기 때문에 큰 문제가 없지만, 컬럼 기반 데이터베이스는 최신 레코드를 얻기 위해서 부하가 발생 할 수 있습니다.
삭제
먼저 물리 삭제와 논리 삭제를 구분해야 합니다. 물리 삭제는 데이터베이스에서 레코드를 영구 삭제하는 것이고 논리 삭제는 레코드에 ‘삭제됨’이라는 표시를 하는 것입니다.
우리가 일반적으로 RDB에서 데이터를 삭제하면 인덱스가 곧바로 삭제되는 것이 아님은 널리 알려져 있습니다. 단지 삭제되었다는 표시를 한 후 인덱스를 비활성화하여 검색 대상에서 제외하는 것인데, 이 부분이 논리 삭제로 볼 수 있습니다.
갱신 입력과 병합
갱신 입력은 일반적으로 RDB에서 조건에 일치하는 행을 찾아서 그 값을 변경하는 것입니다. 그리고 병합은 그 과정에서 레코드를 삭제하는 기능을 추가하는 것 입니다.
왜 병합이 갱신과 삭제와 관련이 있지?라는 생각이 들었습니다. 그리고 그 이유는 바로 파일 기반 스토리지의 경우에는 갱신이 곧 삭제이기 때문입니다.
대표적으로 HDFS의 경우에는 물론 약간의 경우 파일에 append를 지원해주지만, 대체로 파일을 통째로 변경하는 전략을 취합니다. 뿐만 아니라 다양한 데이터 스토리지 및 웨어하우스(일반적으로 OLAP 이기 때문에)에서도 데이터를 갱신하는 명령은 기존의 데이터를 삭제하고 새로운 데이터와 병합 된 형태인 파일을 저장하는 방식으로 동작합니다.
이러한 동작으로 대규모 갱신의 경우에는 병합 과정에서 OLAP가 좋은 성과를 낼 수 있지만, 작은 갱신은 매우 좋지 않은 성과를 낸다고 합니다. 그래서 CDC를 통한 갱신 시스템을 개발한다면 OLAP성 데이터 웨어하우스와 사용하는 것에 주의해야 합니다.
하지만 빅쿼리의 경우 스트리밍 데이터를 실시간으로 입력 할 수 있고 드루이드는 스토리지와 SSD를 사용해 초고속 실시간 쿼리를 지원한다고 합니다.
랭글링
지저분한 잘못 된 형식의 데이터를 유용하고 깨끗한 데이터로 변환하는 작업 이라고 합니다.
페더레이션 쿼리
OLAP 데이터베이스가 객체 스토리지나 RDBMS 등의 외부 데이터 원천에서 조회 할 수 있도록 허용해주는 데이터베이스 기능입니다.
데이터 가상화
데이터를 내부에 저장하지 않는 데이터 처리 및 쿼리 시스템입니다. 여기서 쿼리 푸시다운이라는 개념이 등장하는데 쿼리 푸시다운은 가능한 한 많은 작업을 소스 데이터베이스로 이동시키는 것이 목표로 이로 인해 가상화 계층에서 연산 부하를 줄이거나 네트워크를 통해 전송하는 데이터의 양을 줄일 수 있습니다.
예로 MySQL에 있는 데이터를 부하가 적은 시간에 미리 쿼리하여 그 결과를 S3에 적재해놓은 뒤 다른 데이터 웨어하우스에서 해당 S3파일을 쿼리하면 MySQL에 부하를 주지 않기 때문에 가상화
마이크로배치 VS 진정한 스트리밍
진정한 스트리밍 시스템(빔, 플링크)의 경우에는 한 번에 하나의 이벤트를 처리 할 수 있도록 설계되어 있기 때문에 부하가 매우 심한 편
마이크로배치는 얼마나 배치를 가질지에 대한 점이 고려사항