본문으로 건너뛰기
최종 수정: 에

Lance 쿼리 모범 사례

이 가이드를 사용하여 Lance 쿼리에 필요한 BE별 캐시 예산과 인덱스 세그먼트 구성을 선택하세요. 먼저 워크로드를 파악하고, 캐시에 유지해야 할 콘텐츠의 크기를 추정한 다음, 목표 동시성에서 검증하세요. 예제는 계획 수립을 위한 출발점이며, 벤치마크로 검증된 최적값이나 BE 메모리 한도가 아닙니다.

노트

Lance Catalog는 실험적 기능으로, Apache Doris 4.2부터 지원됩니다. 먼저 Lance Catalog를 참고하여 액세스를 구성하고 리더 호환성을 확인하세요. Doris는 기존 Lance 인덱스를 읽습니다. 인덱스를 구축하거나 유지 관리할 때는 호환되는 Lance 도구를 사용하세요.

스칼라 필터를 벡터 검색 또는 전문 검색과 함께 사용하는 경우, 필터 적용 위치, 인덱스 간 정합성을 맞춘 구축, Profile 진단에 대해서는 Lance 하이브리드 검색 성능 모범 사례를 참고하세요.

1. 튜닝 경로 선택​

워크로드시작할 작업검증 항목
단일 쿼리 지연 시간이 짧아야 하는 벡터 검색자주 탐색하는 벡터 파티션을 유지하고, 세그먼트 가이드를 사용하여 쿼리를 실행할 수 있는 BE 수에 맞춰 균형 있게 나눈 세그먼트 수를 비교유사한 재현율에서의 P95 지연 시간, 가장 느린 스캐너, 최대 메모리 사용량
동시성이 높은 벡터 검색서로 다른 쿼리 벡터가 접근하는 자주 사용하는 파티션의 합집합을 기준으로 예산을 산정하고, 쿼리마다 분할 수를 최대화하기보다 동시 검색에 필요한 메모리와 CPU를 확보목표 동시성에서의 처리량과 P95 지연 시간, 캐시 재적재, BE별 메모리 사용량
BTree 범위/포인트 필터 또는 Bitmap/LabelList 필터조회 구조를 포함하여 자주 사용하는 페이지 또는 비트맵 항목의 크기를 추정하고, 조건식/인덱스 사용 여부를 확인페이지 적재, 선택도, 임시 행 ID 집합, 출력 컬럼 읽기
전문 검색 또는 구문 검색사전, 문서 메타데이터, 포스팅과 활성화된 경우 위치 정보의 크기를 추정하고, 워밍업에 다양한 검색어를 포함빈도가 높은 검색어 쿼리, 구문 쿼리 메모리, 후보 병합
BE를 공유하는 벡터, 스칼라 및 전문 검색 쿼리각 쿼리의 공유 작업 집합을 합산하고 함께 테스트한 쿼리 유형이 다른 유형의 캐시 항목을 제거하는지 여부
출력 컬럼 가져오기 또는 스캔이 대부분을 차지하는 경우데이터 파일 읽기와 별도의 디스크 데이터 캐시를 점검유효 바이트와 읽기 증폭의 비교, 디코딩 또는 데이터 가져오기가 대부분을 차지하는지 여부

스칼라 필터는 벡터 쿼리의 Prefilter에 포함될 수도 있으므로, 하나의 쿼리에 스칼라 인덱스와 벡터 인덱스 콘텐츠가 모두 필요할 수 있습니다. 시나리오를 상호 배타적인 것으로 보지 말고 해당하는 행을 모두 선택하세요.

2. 입력 정보 수집 및 메모리 예산 설정​

각 BE 또는 실제 배치 조건을 반영한 대표 BE에 대해 다음 정보를 수집하세요.

  • 워크로드: 목표 QPS/동시성, 지연 시간 목표, 필요한 재현율, top_k, 필터, 구문 쿼리, 출력 컬럼.
  • 리소스: 쿼리를 실행할 수 있는 BE, CPU 용량, 다른 Doris 워크로드와 프로세스/OS에 필요한 메모리를 제외하고 사용 가능한 메모리.
  • 인덱스: 유형, 버전, 물리적 세그먼트 수, 인덱스 적용 범위, 벡터 차원/인코딩, IVF 파티션 수, 스칼라 값의 너비 또는 문자열 길이.
  • 재사용: 대표적인 쿼리 구간에서 접근하는 서로 다른 파티션, 페이지, 검색어 또는 비트맵 항목. 단일 쿼리가 반환하는 행이 아니라 여러 쿼리에 걸친 작업 집합을 사용하세요.
  • 쿼리 최대 사용량: 목표 동시성에서 진행 중인 파티션 적재, Prefilter/결과 행 ID 집합, 후보 힙, 디코딩, refinement, 두 번째 단계의 데이터 가져오기에 필요한 메모리.

인덱스 계산식으로 페이로드를 추정한 다음, 합산한 예산이 가용 범위에 들어가는지 확인하세요.

available_Lance_cache_budget_on_BE
= BE memory budget
- other BE memory needs
- peak concurrent query working memory
- safety headroom

index_cache_target + metadata_cache_target
<= available_Lance_cache_budget_on_BE

이는 계획을 위한 점검이며, 메모리 예약을 강제하지 않습니다. 캐시 용량은 쿼리 메모리나 프로세스 RSS의 상한이 아닙니다. 재사용 가능한 캐시 작업 집합에 동시 쿼리 수를 곱하지 마세요. 대신 동시 쿼리에 추가로 필요한 작업 메모리를 확보하고, 동시 쿼리가 서로 다른 데이터에 접근할 때 캐시 콘텐츠의 합집합이 커지는 점을 반영하세요.

전체 매개변수 정의와 기본값은 BE 구성에 있습니다. 각 BE의 be.conf에 lance_* BE 매개변수를 설정하고 해당 BE를 다시 시작하세요. 이 매개변수는 Catalog 속성이나 SQL 세션 변수가 아닙니다. 인덱스 세그먼트 수와 IVF 구축 매개변수는 이러한 캐시 매개변수가 아니라 Lance 인덱스 구축 도구로 설정합니다.

3. 인덱스 작업 집합 추정​

각 BE가 재사용해야 하는 인덱스 파티션을 기준으로 인덱스 캐시 크기를 산정하세요. 스토리지에 있는 전체 인덱스, 캐시된 작업 집합, 쿼리의 최대 메모리 사용량은 서로 다른 값입니다. 아래 추정 방법은 Doris에서 지원하는 여섯 가지 벡터 인덱스 유형을 다룹니다. 이는 계획용 추정치이며, 정확한 캐시 사용량 계산이나 메모리 한도가 아닙니다.

인덱스 유형별 벡터 페이로드​

다음 기호를 사용합니다. 모든 계산식의 결과는 바이트 단위이며, 1 GiB = 1073741824 bytes입니다.

기호의미
N추정 대상 파티션에 인덱싱된 벡터 수. 일반적인 단일 벡터 컬럼에서는 인덱싱된 행 수입니다. 다중 벡터 컬럼에서는 인덱싱된 하위 벡터 수를 세고, 행 매핑과 refinement에 필요한 공간을 별도로 반영하세요.
D벡터 차원.
w양자화하지 않고 저장한 벡터 요소당 바이트 수. Float16은 2, Float32는 4, Float64는 8입니다. 바이너리 uint8 벡터는 실제 바이트 길이를 D로 사용하고 w=1로 설정하세요.
m, bPQ 하위 벡터 수와 하위 벡터 코드당 비트 수. 쿼리 매개변수가 아니라 인덱스 구축 설정입니다.
G모든 레벨과 보조 구조를 포함하여, 적재된 HNSW 그래프가 차지하는 메모리.

벡터 코드만이 아니라 해당하는 구성 요소를 모두 합산하세요. 첫 번째 표는 벡터당 페이로드를 구분하며, 이어지는 표는 공유 구조와 HNSW 그래프 구성 요소를 나열합니다. 모든 계산식은 적재된 버퍼의 크기를 추정합니다. 측정으로 표시된 행도 예산이 필요하며, 비용이 없는 항목이 아닙니다. 공유 할당은 각각 한 번만 계산하세요.

인덱스 유형벡터 값 / 코드UInt64 행 IDHNSW 그래프그 밖에 필요한 예산
IVF_FLATN * D * w8 * N없음IVF 구조 + 아래의 공통 오버헤드
IVF_SQSQ8의 경우 N * D8 * N없음IVF 구조 + SQ 메타데이터 + 공통 오버헤드
IVF_PQN * ceil(m * b / 8)8 * N없음IVF 구조 + PQ 코드북 + 공통 오버헤드
IVF_HNSW_FLATN * D * w8 * NG 추가IVF 구조 + 공통 오버헤드
IVF_HNSW_SQSQ8의 경우 N * D8 * NG 추가IVF 구조 + SQ 메타데이터 + 공통 오버헤드
IVF_HNSW_PQN * ceil(m * b / 8)8 * NG 추가IVF 구조 + PQ 코드북 + 공통 오버헤드

PQ에서 b=8이면 코드는 벡터당 m바이트를 차지합니다. b=4이면 m/2바이트를 차지하며, 이는 지원되는 짝수 m에 해당합니다. 예를 들어 벡터 1백만 개에 m=96과 b=8을 사용하면 코드가 96000000바이트, 행 ID가 8000000바이트로, 합계 104000000바이트(약 99.2 MiB)입니다. 압축률이 높은 인덱스의 크기를 추정할 때도 행 ID를 생략하면 안 됩니다.

추가 구성 요소적용 대상적재된 페이로드 / 예산 산정 방법
IVF 중심점여섯 유형 모두FP32: 유지하는 중심점 집합당 num_partitions * D * 4. 다른 레이아웃에서는 실제 요소 너비를 사용
IVF 파티션 디렉터리 / 하위 인덱스 메타데이터여섯 유형 모두유지되는 파티션 오프셋, 길이, 리더 구조를 측정. 벡터 값 및 중심점과는 별개
PQ 코드북IVF_PQ, IVF_HNSW_PQ표준 FP32 코드북: 유지하는 복사본당 2^b * D * 4
SQ 양자화기 메타데이터IVF_SQ, IVF_HNSW_SQ유지되는 양자화기 경계/매개변수를 측정. 버전마다 동일한 고정 레이아웃을 사용한다고 가정하지 않음
노름, 행 적용 범위 구조, 추가 매핑리더가 유지하는 경우실제 배열/집합을 측정. 다중 벡터의 행 매핑에는 별도 예산 필요
인덱스 객체, Arrow 유효성 버퍼, 여유 용량 및 복사본여섯 유형 모두논리적 페이로드 외의 할당을 측정. 공유 버퍼는 한 번만 계산

독립적인 인덱스 세그먼트는 중심점 집합과 코드북을 각각 유지할 수 있습니다. 공유 할당에 모든 파티션 수를 곱하거나 모든 복사본이 공유된다고 가정하지 마세요. 추가 구조는 내장된 Lance 버전에 따라 달라집니다.

HNSW 그래프 구성 요소​

그래프는 벡터 코드 및 행 ID에 추가되는 항목입니다. UInt32 노드/이웃 ID와 선택적으로 유지되는 Float32 간선 거리를 사용하는 Arrow 기반 Lance 그래프에서, E는 적재된 모든 레벨에 저장된 방향성 이웃 항목 수, V는 해당 레벨 전체의 노드 출현 횟수, A는 독립적으로 유지되는 그래프 배치 수를 나타냅니다. 여러 레벨에 존재하는 노드는 V에 여러 번 포함됩니다.

그래프 구성 요소주요 페이로드, 바이트 단위계산 규칙
이웃 ID4 * E방향성 이웃 항목당 UInt32. 모든 레벨을 포함하여 계산
저장된 간선 거리4 * E이웃 항목당 Float32. 리더가 거리 컬럼을 건너뛰면 공간을 차지하지 않음
그래프 노드 ID4 * V노드 출현당 UInt32. 데이터셋의 UInt64 행 ID와는 별개
이웃 목록 오프셋4 * (V + A)배치당 마지막 오프셋 하나를 포함하는 Int32 목록 오프셋
거리 목록 오프셋4 * (V + A)두 번째 Int32 목록 오프셋 배열. 리더가 거리 컬럼을 건너뛰면 공간을 차지하지 않음
거리를 포함한 소계8 * E + 12 * V + 8 * A큰 배치에서는 대략 8 * E + 12 * V. 전체 G는 아님
거리를 제외한 소계4 * E + 8 * V + 4 * A노드 ID와 이웃 목록만 유지할 때 사용. 두 소계를 합하지 말고 하나만 선택
레벨 오프셋, 진입점 및 노드 조회 구조측정적재된 각 그래프에서 유지하는 메타데이터와 조회용 할당을 포함
유효성 버퍼, 그래프 객체 및 여유 할당 용량측정공유 버퍼를 중복 계산하지 않고 위 버퍼 외의 실제 할당을 추가
전체 그래프 예산 G주요 소계 + 측정한 그래프 추가 항목벡터/행 ID 페이로드 및 다른 인덱스 구조에 이 값을 추가

이는 특정 레이아웃에 대한 추정치이며, 노드당 바이트 수를 고정적으로 보장하지 않습니다. HNSW의 m은 그래프 연결성을 제어하며 PQ의 m과는 관련이 없습니다. N * m * 4를 G 대신 사용하지 마세요. 실제 차수, 상위 레벨, 유지되는 거리, 리더 버전이 영향을 줍니다. 대표 파티션을 적재하고 유지되는 할당을 측정하여 추정치를 보정하세요.

예를 들어, 캐시된 IVF_HNSW_PQ 파티션에 벡터 1백만 개가 있고, PQ m=96, b=8, E=32000000, V=1100000, A=1이라고 가정하겠습니다. 이 리더는 거리 컬럼을 유지한다고 가정합니다. 이 그래프 개수는 설명을 위한 입력값이며, HNSW의 m에서 도출한 값이 아닙니다.

구성 요소예제 페이로드
PQ 코드96000000바이트
데이터셋 행 ID8000000바이트
주요 그래프 버퍼8 * 32000000 + 12 * 1100000 + 8 = 269200008바이트, 약 256.7 MiB
코드 + 행 ID + 주요 그래프 버퍼373200008바이트, 약 355.9 MiB
대안: 거리를 건너뛸 때의 주요 그래프 버퍼4 * 32000000 + 8 * 1100000 + 4 = 136800004바이트, 약 130.5 MiB
대안 합계: 코드 + 행 ID + 거리를 제외한 그래프 버퍼240800004바이트, 약 229.6 MiB
두 경우 모두 추가해야 하는 항목위 표의 그래프 추가 항목, IVF 중심점/디렉터리, PQ 코드북, 공통 오버헤드

리더가 유지하는 컬럼에 맞는 예제를 선택하세요. 어느 소계도 완전한 캐시 용량 권장값은 아닙니다.

업스트림 Lance 성능 가이드는 벡터 페이로드와 인덱스 구축 메모리 추정 방법을 설명합니다. Lance 벡터 인덱스 형식은 IVF 파티션, 하위 인덱스, 양자화 스토리지가 어떻게 분리되는지 설명합니다. 최신 문서에는 Doris에 내장된 Lance 버전보다 새로운 기능이 포함될 수 있으므로, 호환성은 Lance Catalog 지원 매트릭스로 확인하세요.

스칼라 및 전문 검색 인덱스 페이로드​

스칼라 인덱스도 크기를 추정할 수 있지만, 입력값은 인덱스 계열마다 다릅니다. 쿼리가 반환하는 행만이 아니라 하나의 BE에 실제로 유지되는 항목을 계산하세요. 다음 방법은 Lance 스토리지 레이아웃을 설명하며, Doris의 조건식 푸시다운 또는 인덱스 호환성 보장 범위를 확장하지 않습니다. 내장된 Lance 버전이 해당 인덱스를 지원하고 쿼리가 이를 사용하는지 확인하세요.

BTree. 적재된 리프 페이지에는 값과 UInt64 행 ID가 포함됩니다. R은 캐시된 리프 페이지의 레코드 수, H는 해당 페이지 수, w는 고정 너비 값의 크기, L은 해당 페이지의 평균 문자열 길이(바이트)를 나타냅니다.

리프 페이지 구성 요소 / 표현값 버퍼오프셋UInt64 행 ID
Int32 / Float324 * R없음8 * R
Int64 / Float64 / 64비트 타임스탬프8 * R없음8 * R
기타 고정 너비 값w * R. 비트 패킹된 Boolean에는 실제 비트맵 버퍼 사용없음8 * R
Arrow Utf8 / BinaryR * LInt32 오프셋의 경우 4 * (R + H)8 * R
Arrow LargeUtf8 / LargeBinaryR * LInt64 오프셋의 경우 8 * (R + H)8 * R

리프 페이지 소계는 페이로드를 나타내는 세 컬럼의 합입니다. 연 각 세그먼트에 대해 다음 구성 요소를 추가하세요. 아래의 P는 캐시된 페이지만이 아니라 해당 세그먼트의 모든 리프 페이지 수를 나타냅니다.

추가 BTree 구성 요소주요 페이로드 / 예산 산정 방법
조회용 최솟값고정 너비 값의 경우 P * w. 가변 너비 값은 실제 값/오프셋 버퍼 사용
조회용 최댓값고정 너비 값의 경우 P * w. 가변 너비 값은 실제 값/오프셋 버퍼 사용
조회용 NULL 개수UInt32 레이아웃의 경우 4 * P
조회용 페이지 번호UInt32 레이아웃의 경우 4 * P
고정 너비 조회 버퍼 소계P * (2 * w + 8). 아래 구조는 제외
NULL 페이지 목록 및 조회 객체유지되는 목록, 객체, 구현별 복사본을 측정
리프/조회 유효성 버퍼, Arrow 객체 및 여유 용량논리적 값/오프셋/행 ID 외의 할당을 측정

문자열 계산식은 표에 나열된 Arrow 레이아웃을 가정합니다. 사전 또는 뷰 표현에는 실제 버퍼 크기가 필요합니다. 디스크 압축률이 디코딩된 페이지 크기를 결정하지는 않습니다. BTree의 기본 페이지 크기는 바이트가 아니라 레코드 4096개입니다. 인덱스의 실제 페이지 크기를 사용하세요. 조회 구조는 페이지를 설명한다는 이유만으로 BE 메타데이터 캐시 예산에 속하는 것이 아니라, 인덱스 작업 집합에 속합니다.

예를 들어 Int64 값 100백만 개의 리프 값/행 ID 페이로드는 100000000 * 16 = 1600000000바이트(약 1.49 GiB)입니다. 캐시된 페이지가 레코드 10백만 개를 포함한다면 해당 페이로드는 약 152.6 MiB입니다. 페이지당 레코드가 4096개이면 전체 인덱스에는 약 24415개의 페이지가 있으며, 조회 배치의 최솟값/최댓값/개수/페이지 번호 페이로드는 추가 구조를 제외하고 약 572 KiB입니다. 일치하는 행을 열 개 반환한다고 해서 레코드를 열 개만 캐시하는 것은 아닙니다. 리더는 페이지를 적재합니다.

Bitmap, LabelList 및 NGram. 아래에서 해당하는 구성 요소 행을 합산하세요. 멤버십 비트맵이 일치하는 행마다 무조건 여덟 바이트를 사용하는 것은 아닙니다. LabelList는 서로 다른 레이블별로 멤버십을 계산하므로 하나의 행이 여러 레이블 비트맵에 나타날 수 있습니다. NGram은 서로 다른 gram/행 멤버십을 계산하며, 한 행에서 같은 gram이 반복되어도 멤버십이 추가되지 않습니다. 이 NGram 인덱스는 n-gram 토크나이저를 사용하는 FTS 인덱스와 다릅니다.

인덱스 계열구성 요소적재된 페이로드 / 예산 산정 방법
Bitmap키 조회유지되는 키 값, 항목 참조, 조회 객체를 측정
LabelList레이블 조회 / 래퍼서로 다른 레이블 키, 항목 참조, 래퍼 객체를 측정
NGramGram 조회유지되는 gram, 항목 참조, 조회 객체를 측정
세 계열 모두멤버십 비트맵: 배열 컨테이너65536개 값 범위에서 UInt16 항목 c개를 포함하는 일반적인 Roaring 배열 컨테이너당 약 2 * c
세 계열 모두멤버십 비트맵: 밀집 컨테이너65536개 값 범위를 포함하는 일반적인 밀집 컨테이너당 8192바이트
세 계열 모두멤버십 비트맵: run / 전체 Fragment 표현실제 표현을 측정. 모든 대안을 합산하지 말고 각 컨테이너에 선택된 표현을 사용
세 계열 모두비트맵 디렉터리 / 용량Fragment/상위 비트 디렉터리, 컨테이너 객체, 여유 용량을 측정
존재하는 경우NULL / NULL 목록 추적유지되는 NULL 멤버십 구조를 별도로 측정
각 계열의 합계조회 + 적재된 멤버십 표현 + 디렉터리 + NULL 추적공유 할당은 한 번만 계산. 직렬화된 비트맵 크기가 상주 메모리 크기를 보장하지는 않음

예를 들어 밀집 컨테이너 256개를 적재하면 비트 집합 페이로드는 2 MiB이며, 이는 키, 디렉터리, NULL 추적, 객체 오버헤드를 추가하기 전의 크기입니다.

기타 스칼라 및 전문 검색 인덱스. 각 행은 별도의 구성 요소를 나타냅니다. 소계 행은 앞선 구성 요소의 합계이므로 다시 더하면 안 됩니다. BE에 유지되는 콘텐츠만 계산하세요. 측정은 해당 구성 요소를 생략해도 된다는 뜻이 아니라, 리더의 실제 할당량이 필요하다는 뜻입니다.

인덱스 계열구성 요소적재된 페이로드 / 예산 산정 방법
FTS / Inverted검색어 사전적재된 검색어, 사전 구조, 조회용 할당을 측정
FTS / Inverted문서 메타데이터유지되는 문서 매핑, 길이, 기타 리더 메타데이터를 측정
FTS / Inverted비압축 포스팅 행 IDUInt64 검색어/문서 항목 T개에 대해 8 * T
FTS / Inverted비압축 포스팅 빈도Float32 빈도에 대해 4 * T. ID + 빈도 합계는 12 * T
FTS / Inverted활성화된 경우 위치 정보저장된 Int32 출현 위치 O개에 대해 4 * O
FTS / Inverted위치 오프셋실제로 유지되는 오프셋 배열의 바이트 수. 4 * O와는 별개
FTS / Inverted압축된 포스팅 레이아웃해당 비압축 레이아웃 계산식 대신 실제로 유지되는 압축 블록을 사용
FTS / Inverted점수 계산 / 블록 메타데이터 및 할당 오버헤드유지되는 블록 기술자, 점수 계산 데이터, 객체, 여유 용량을 측정
ZoneMap최솟값적재된 영역 Z개와 너비가 w인 고정 너비 값에 대해 논리적 크기 Z * w바이트
ZoneMap최댓값논리적 크기 Z * w바이트. 최솟값 + 최댓값 합계는 2 * Z * w
ZoneMap개수 및 영역 경계유지되는 개수와 경계를 측정. 부분 영역을 포함하여 Fragment별 영역 수를 계산
ZoneMapNULL 추적 및 박싱된 값/객체 오버헤드선택적 NULL 행 집합과 실제 스칼라 할당을 측정. 이 크기가 논리적 최솟값/최댓값 바이트 수를 크게 초과할 수 있음
BloomFilter필터 비트 배열실제 할당된 필터 바이트 수를 합산. 각각 F바이트인 동일 크기의 필터 Z개라면 Z * F
BloomFilter영역 기술자 / 필터 객체유지되는 기술자, 필터 매개변수, 객체 오버헤드를 측정
BloomFilterNULL 추적선택적 NULL 행 집합을 측정
RTree경계 상자 좌표2D 항목당 Float64 좌표 네 개에 대해 32 * Q. 캐시된 모든 트리 레벨에 걸쳐 항목 Q개를 계산
RTree행 / 자식 페이지 IDUInt64 ID에 대해 8 * Q. 좌표 + ID 합계는 40 * Q
RTree트리 메타데이터 및 페이지 오프셋유지되는 트리 기술자와 페이지 오프셋 버퍼를 측정
RTreeNULL 추적, Arrow/객체 및 여유 용량실제 추가 할당을 측정
JSON 경로 래퍼기반 인덱스선택한 스칼라 인덱스 계열의 전체 구성 요소 예산을 사용
JSON 경로 래퍼경로 및 래퍼 구조기반 인덱스 외에 유지되는 경로와 래퍼 할당을 측정

Bloom 필터에는 빌더가 블록 단위로 올림하여 실제 할당한 크기가 필요합니다. 행 수와 오탐 확률만으로 모든 레이아웃을 설명할 수는 없습니다. 익숙하지 않거나 실험적인 레이아웃에서는 다른 계열의 계산식을 적용하지 말고 적재된 할당을 측정하세요. 일치하는 행이 적더라도 사전, 트리 또는 문서 메타데이터가 상당히 많이 필요할 수 있습니다.

쿼리 작업 메모리는 모든 캐시 표와 별도로 산정하세요. 임시 교집합/합집합, 결과 행 ID 집합, 근사 필터의 재검사, 정확한 RTree 검사를 위한 원본 지오메트리 읽기, 출력 컬럼 읽기에는 각각 예산이 필요합니다.

기반 구조에 대해서는 업스트림 BTree 형식, Bitmap 형식, FTS 형식을 참고하세요. 위 계산식은 적재된 페이로드를 추정하며, 압축된 파일 크기나 전체 쿼리 RSS를 추정하지는 않습니다.

인덱스 크기에서 BE별 작업 집합으로​

세그먼트 s에 대해, N_s는 인덱싱된 벡터 수, P_s는 IVF 파티션 수, H_s는 특정 BE에 유지할 서로 다른 파티션 수를 나타냅니다. 파티션이 적절히 균형을 이루면 다음과 같습니다.

cached_vectors_on_BE ≈ sum over segments (N_s * H_s / P_s)
index_cache_target ≈ cached vector/row-ID payload
+ cached HNSW graphs
+ centroids, codebooks and other index allocations
+ measured headroom

파티션이 편향되어 있으면 실제 파티션 행 수를 사용하세요. H_s는 단일 쿼리의 nprobes만이 아니라 여러 쿼리에 걸친 작업 집합을 나타냅니다. 다양한 쿼리는 결국 모든 파티션에 접근할 수 있으며, 반복 쿼리나 동시 쿼리는 동일한 캐시 파티션을 공유할 수 있습니다. 서로 다른 (dataset, index segment, partition) 항목을 세고, 해당 BE가 접근하는 모든 테이블, 인덱스, 버전을 포함하세요. 한 BE의 캐시 상주 상태가 다른 BE의 캐시를 워밍업하지 않으며, 스케줄링이 각 인덱스 세그먼트를 항상 하나의 BE에 유지한다고 보장하지도 않습니다. 관측한 배치와 재사용 양상이 뒷받침하지 않는 한, 전체 인덱스 크기를 BE 수로 나누지 마세요.

쿼리 실행 시 메모리는 추가로 필요합니다. 진행 중인 파티션 적재, 캐시에서 제거된 뒤에도 쿼리가 참조하고 있는 객체, Prefilter 상태, 거리 테이블, 후보 힙, 디코딩된 배치, refinement, 두 번째 단계의 데이터 가져오기가 여기에 포함됩니다. top_k, ef, refine_factor, 스캔 동시성, nprobes는 이 메모리나 접근하는 작업 집합에 영향을 주지만, 벡터당 저장 바이트 수를 바꾸지는 않습니다. 설정된 캐시 용량은 Lance 또는 BE RSS의 엄격한 상한이 아닙니다. 캐시를 늘려도 거리 계산이나 쿼리별 필터링 작업이 없어지지는 않습니다.

구성 예제 및 튜닝​

FP32, 768차원의 IVF_PQ 인덱스에 벡터 100백만 개가 있고, m=96, b=8이며, 하나의 인덱스 세그먼트에 균형 잡힌 파티션 4096개가 있다고 가정하겠습니다. 한 BE의 대표 워크로드가 서로 다른 파티션 1024개에 반복적으로 접근합니다.

Full code/row-ID payload = 100000000 * (96 + 8) = 10400000000 bytes ≈ 9.69 GiB
Cached payload = 10400000000 * 1024 / 4096 = 2600000000 bytes ≈ 2.42 GiB
IVF centroids = 4096 * 768 * 4 = 12582912 bytes = 12 MiB
PQ codebook = 256 * 768 * 4 = 786432 bytes = 0.75 MiB

이것이 BE에서 유일하게 큰 인덱스 작업 집합이고 메모리 예산이 허용한다면, 이 예제에서는 인덱스 캐시의 초기 할당량으로 4 GiB가 적절합니다. 계산한 페이로드 외에 추가 인덱스 할당을 위한 여유를 남길 수 있기 때문입니다. 이는 검증할 초기값이며, 보편적인 오버헤드 비율이 아닙니다. 반대로 워크로드에서 전체 인덱스를 메모리에 상주시켜야 한다면 4 GiB는 부족하며, 기본값인 10 GiB조차 다른 할당을 더하기 전의 페이로드 9.69 GiB에 가깝습니다.

최대 쿼리 메모리, 다른 Doris 워크로드, 프로세스/OS 여유 공간과 함께 인덱스 캐시 4 GiB 및 메타데이터 캐시 1 GiB를 수용할 수 있는 BE에서는 다음과 같이 설정하세요.

lance_index_cache_size_bytes = 4294967296
lance_metadata_cache_size_bytes = 1073741824

설정을 적용하려면 해당 BE를 다시 시작하세요. 각 BE에 예산을 별도로 적용하세요. 이 설정은 BE 구성 매개변수이며, Catalog 속성이나 SQL 세션 변수가 아닙니다.

  1. 서로 다른 쿼리 벡터, 필터, 테이블을 포함하여 대표 쿼리와 동시성으로 워밍업하세요. 하나의 벡터만 반복하면 다양한 워크로드의 작업 집합을 과소평가하게 됩니다.
  2. doris_be_lance_session_index_cache_usage_bytes를 doris_be_lance_session_index_cache_capacity_bytes와 비교하고, 구간별 hits_total/misses_total 증가량을 관찰하세요. 완료된 각 쿼리에서는 LanceIndexCacheHits, LanceIndexCacheMisses, LanceIndexObjectLoads, LanceIndexComponentsLoaded도 LanceIndex 아래에서 확인하세요. 쿼리의 캐시 조회와 구성 요소 적재는 범위가 서로 다르며, BE 전체 메트릭의 변화량과도 서로 대체할 수 없습니다. 사용량이 용량에 근접한 상태에서 미스가 지속되면 캐시 교체가 빈번하다는 신호일 수 있습니다. 그러나 새 파티션, 인덱스 버전, 서로 다른 BE, 콘텐츠를 유지하지 않는 스트리밍 경로도 미스의 원인이 될 수 있습니다. 재사용과 가용 메모리가 뒷받침할 때만 용량을 늘리세요.
  3. BE 메모리 예산이 허용하면 메타데이터 캐시 크기는 기본값인 1 GiB에서 시작하세요. usage_bytes와 적중/미스 메트릭을 사용하여 조정하세요. 파일/Fragment 수, 스키마/페이지 메타데이터, 삭제 정보, 행 ID 매핑이 수요를 결정하며, 벡터 인덱스 크기의 일정 비율로 정해지는 것이 아닙니다. BE 메타데이터 캐시는 FE 테이블 액세스 캐시와 별개입니다.
  4. 어느 캐시든 늘리기 전에 목표 동시성에서 BE 프로세스 메모리와 쿼리의 최대 사용량을 확인하세요. 캐시 적중률이 높은데 지연 시간도 길다면 점수 계산, Prefilter, 디코딩 또는 데이터 가져오기 비용이 원인일 수 있습니다. 캐시를 추가하는 것이 반드시 도움이 되지는 않습니다.
  5. refinement와 출력 컬럼 가져오기 같은 반복적인 데이터 파일 읽기에 대해서는 lance_data_cache_disk_capacity_bytes의 크기를 독립적으로 산정하세요. 이 값을 늘려도 인덱스 캐시가 커지거나 인덱스 캐시 미스가 보완되지는 않습니다. 인덱스 파일은 이 디스크 데이터 캐시를 우회합니다. 처음에는 lance_data_cache_read_block_size_bytes를 기본값인 1 MiB로 유지하고, 유효 읽기와 읽기 증폭을 측정한 뒤에만 변경하세요.

4. 공유 캐시 예산 산정​

각 BE에서 Lance는 공유 세션과 하나의 인덱스 캐시 용량을 사용합니다. 벡터 파티션, BTree 페이지, Bitmap/LabelList 항목, 전문 검색 인덱스 콘텐츠는 이 공간을 놓고 경쟁할 수 있습니다. 동일한 BE에서 접근하는 서로 다른 테이블과 Catalog의 인덱스도 여기에 포함됩니다. 캐시 키는 각 항목을 구분하지만 용량을 예약하지는 않습니다. Lance BE 캐시 설정은 테이블별 또는 인덱스 유형별 할당량이나 고정 유지 제어를 제공하지 않습니다.

적재된 콘텐츠만 캐시 공간을 사용합니다. 인덱스를 여러 개 생성하는 것만으로 모두 적재되지는 않습니다. 쿼리가 인덱스를 사용하기 시작하면 한 인덱스를 적재하면서 다른 인덱스의 항목이 제거될 수 있습니다. 예를 들어 넓은 범위의 BTree 스캔이나 다양한 FTS 쿼리는 워밍업된 벡터 파티션을 대체할 수 있습니다. 이후 벡터 쿼리는 해당 파티션을 다시 적재합니다. 인덱스 버전이 바뀌어도 이전 항목이 상주한 상태에서 새 항목이 추가될 수 있습니다. 실행 중인 쿼리가 여전히 참조하는 객체는 캐시에서 제거되어도 즉시 해제되지 않습니다.

공유 할당을 중복 계산하지 않고 혼합 작업 집합을 계획하세요.

index_cache_target_on_BE ≈ vector working set
+ BTree working set
+ Bitmap / LabelList / NGram working sets
+ FTS and other index working sets
+ measured headroom

예를 들어 측정값과 페이로드 추정치가 인덱스 구조를 포함하여 벡터 2.5 GiB, BTree 0.25 GiB, Bitmap 0.5 GiB, FTS 0.75 GiB라고 가정하겠습니다. 합산한 작업 집합은 4 GiB입니다. 초기 인덱스 캐시를 5 GiB로 설정하면 증가분과 추정 오차를 위해 1 GiB를 남길 수 있지만, 모든 워크로드를 수용한다고 보장하지는 않습니다. BE에 메타데이터 캐시 1 GiB와 함께 최대 쿼리 메모리, 다른 Doris 워크로드, 프로세스/OS 여유 공간까지 수용할 수 있다면 다음과 같이 설정하세요.

lance_index_cache_size_bytes = 5368709120
lance_metadata_cache_size_bytes = 1073741824

인덱스 캐시와 메타데이터 캐시는 용량이 별개입니다. 메타데이터 항목이 인덱스 항목을 직접 제거하지 않으며, 한쪽을 늘려도 다른 쪽이 커지지 않습니다. 하지만 둘 다 동일한 BE 프로세스 메모리를 사용합니다. 디스크 데이터 캐시는 세 번째 예산이며, 인덱스 파일을 캐시하지 않습니다. 동일한 BE에서 Catalog를 분리해도 인덱스 캐시가 격리되지는 않습니다. 격리가 필요한 워크로드에는 별도의 BE 리소스와 해당 배포 환경에서 지원하는 라우팅이 필요합니다.

경합을 진단하려면 먼저 한 쿼리 유형을 워밍업하고 지연 시간과 캐시 메트릭 변화량을 기록하세요. 두 번째 유형을 실행한 다음 첫 번째 유형을 다시 실행하세요. 인덱스 버전과 BE 배치가 유사하게 유지되었다는 전제하에, 캐시 사용량이 용량에 근접한 상태에서 미스나 재적재가 다시 발생하면 캐시 제거 압력이 있다는 신호입니다. 세션 적중/미스 메트릭은 여러 워크로드를 집계하므로 쿼리 수준의 LanceIndexCacheHits/LanceIndexCacheMisses, LanceIndexComponentsLoaded, LanceIOReadBytes와 함께 확인하세요. 구성 요소 적재 횟수는 미스 횟수가 아니며, 실행 중 읽은 바이트 수는 측정된 원격 트래픽이 아닙니다. 모든 인덱스를 미리 워밍업하는 작업 자체가 유지하려던 작업 집합을 제거할 수 있습니다. 대표적인 혼합 워크로드로 워밍업하고, 재사용과 가용 메모리가 뒷받침할 때만 용량을 늘리세요.

5. 인덱스 세그먼트의 세분화 수준 선택​

Index Segment, 데이터 Fragment, IVF 파티션, BTree 리프 페이지는 서로 다른 단위입니다. 현재 Doris 벡터 검색 경로에서는 선택한 각 물리적 Index Segment가 하나의 스캔 Split이 되며, 인덱스가 적용되지 않은 Fragment는 Flat Search Split을 추가합니다. FTS도 물리적 인덱스 세그먼트를 사용합니다. 하나의 벡터 세그먼트에 속한 IVF 파티션이 개별 Doris Split이 되어 여러 BE에 분산되는 것은 아닙니다. Lance는 내부적으로 작업을 병렬 실행할 수 있습니다. 일반적인 스칼라 스캔에서 세그먼트 기반 그룹화는 선택한 인덱스와 실행 계획에 따라 달라집니다. 모든 스칼라 인덱스가 벡터 검색의 Split 정책을 따른다고 가정하지 마세요.

B는 이 쿼리를 실제로 실행할 수 있는 BE 수, S는 선택한 벡터 세그먼트 수를 나타냅니다. S가 B보다 작으면, 해당 쿼리에서 모든 BE를 활용하기에는 인덱스 스캔 Split이 부족합니다. S를 늘리면 스케줄링 기회가 생기지만, 모든 Split이 동시에 실행된다는 보장은 없습니다. 스캐너 제한, Lance 내부 동시성, CPU, I/O, 캐시 상주 상태, 동시 쿼리도 영향을 줍니다. Doris 파이프라인 인스턴스만 늘려서는 하나의 인덱스 세그먼트를 세분화할 수 없습니다.

대규모 데이터셋에서는 균형 있게 나눈 벡터 세그먼트 B개, 2 * B개, 4 * B개를 초기 실험으로 비교하세요. 이는 공식적인 최적값이나 소규모 데이터셋에 대한 요구 사항이 아닙니다. 설명을 위해 벡터 100백만 개와 쿼리를 실행할 수 있는 BE 여덟 개가 있는 데이터셋을 예로 들겠습니다.

세그먼트 수세그먼트당 평균 벡터 수평가 항목
812.5백만 개BE 전체를 활용하기에 충분한 Split과 적은 세그먼트별 작업
166.25백만 개스케줄링 유연성 향상과 하나의 큰 세그먼트에 대한 민감도 감소
323.125백만 개작업 수 증가와 함께 검색, 적재, 병합 오버헤드가 커질 가능성

Fragment 수만이 아니라 예상 검색 작업량과 적재되는 인덱스 바이트 수의 균형을 맞추세요. 차원과 인코딩이 같은 벡터에서는 행 수를 균등하게 나누는 것이 유용한 출발점입니다. 하지만 HNSW 그래프 크기, IVF 편향, 스칼라 선택도, 문서 길이에 따라 균형이 달라질 수 있습니다. 세그먼트당 행 수나 파일 크기에 보편적으로 적용되는 임계값은 없습니다. 처리량이 높은 워크로드에서는 동시 쿼리를 위한 용량을 확보하도록 쿼리당 작업 수를 줄이는 편이 유리할 수 있습니다. 단일 쿼리의 지연 시간은 Split을 늘리면 개선될 수 있습니다.

세그먼트가 많아지면 세그먼트별 초기 설정, 메타데이터/양자화기 객체, 로컬 후보 생성도 늘어납니다. 각 벡터/FTS Split은 최대 top_k + offset개의 후보를 유지하며, Doris는 이 한도를 S로 나누지 않습니다. 따라서 스캔 측 후보 수의 상한은 일치하는 항목 수에 따라 S * (top_k + offset)이 됩니다. top_k=1000, 오프셋 없음, Split 32개라면 Doris가 후보를 축소하기 전에는 최대 32000개의 후보가 생깁니다. 로컬 TopN은 네트워크 트래픽을 줄일 수 있으므로, 이 값이 네트워크로 전송되는 행 수를 보장하지는 않습니다. top_k가 클수록 후보 처리의 영향이 커집니다.

세그먼트 수는 각 세그먼트의 IVF num_partitions 및 쿼리 nprobes와 함께 조정하세요. 파티션이 균형을 이루면 대략적인 탐색 벡터 수는 sum(N_s * nprobes_s / P_s)이며, 각 세그먼트에서 N_s를 상한으로 합니다. 이는 HNSW 비교 횟수를 계산하는 식이 아닙니다. 세그먼트를 재구축하거나 파티션 수를 변경하면 같은 nprobes에서도 재현율이 달라질 수 있으므로, 유사한 재현율에서 지연 시간을 비교하세요. HNSW ef와 refinement 설정도 비교에 영향을 줍니다.

Lance 도구로 세그먼트를 구축하고 유지 관리한 다음, 의도한 논리적 인덱스로 커밋하세요. 이름이 다른 전체 테이블 인덱스 여러 개는 물리적 세그먼트가 여러 개인 하나의 인덱스를 대체할 수 없습니다. 온전한 Fragment를 균형 잡힌 그룹으로 묶는 방식을 권장하며, 소규모 추가로 인해 작은 세그먼트가 많이 누적되지 않도록 하세요. 내장된 Lance 버전에서 지원하는 유지 관리 API를 사용하세요. 결과로 생성된 물리적 세그먼트 수와 인덱스가 적용되지 않은 Fragment 수는 Doris EXPLAIN/Profile에서 확인하세요. SHOW INDEX의 행 수로 추정하지 마세요. 모든 세그먼트를 하나로 병합하면 Doris 스캔 병렬성이 줄어들 수 있습니다. 세그먼트 구축 및 커밋 개념은 Lance 분산 인덱싱을 참고하세요.

BTree 포인트 조회나 선택도가 높은 Bitmap 쿼리는 세그먼트를 많이 나누면 세그먼트당 줄어드는 작업은 적은데 조회와 열기 작업만 추가될 수 있습니다. FTS에는 세그먼트별 사전/포스팅 검색과 후보 병합이 추가됩니다. 벡터 세그먼트 수를 모든 인덱스 계열에 적용하지 말고 이러한 워크로드를 별도로 평가하세요. 분할해도 불필요한 행별 Prefilter 생성이 사라지지는 않습니다. 리더의 필터링 동작을 독립적으로 확인하세요.

6. 혼합 워크로드 검증​

  1. 인덱스 선택, 물리적 Split, 인덱스 적용 범위를 확인하세요. 지연 시간을 분석할 때 대체 스캔과 두 번째 단계의 데이터 가져오기도 포함하세요.
  2. 각 인덱스가 유지하는 페이로드를 추정하고 공유 작업 집합을 합산하세요. 병렬 적재, 행 ID 집합, 후보 힙, 디코딩을 포함한 쿼리 메모리는 별도로 확보하세요.
  3. 실제적인 동시성에서 콜드 캐시와 워밍업된 혼합 워크로드를 비교하세요. P95 지연 시간, 처리량, 해당하는 경우 재현율, BE별 최대 메모리 사용량, 캐시 사용량과 적중/미스 변화량, 인덱스 적재 I/O, 스캔 시간 불균형을 추적하세요.
  4. 캐시 용량, 세그먼트 수, 검색 매개변수 중 한 번에 하나만 변경하세요. 세그먼트 재구축으로 모델이 달라지면 재현율을 다시 확인하세요. 처리량, 지연 시간 또는 메모리가 더 이상 개선되지 않으면 Split이나 캐시를 늘리는 작업을 멈추세요.
  5. 대규모 데이터 추가, 인덱스 재구축, BE 확장/축소 또는 쿼리 구성 변경 후에 다시 검증하세요. 하나의 벡터나 테이블을 기준으로 보정한 구성이 모든 워크로드에서 안정적인 예산이 되는 것은 아닙니다.

7. 리소스를 늘리기 전에 진단​

관측된 현상먼저 확인할 항목검토할 조치
캐시 사용량이 용량에 근접한 상태에서 인덱스 미스가 반복됨인덱스/버전 변경, BE 배치, 합산한 작업 집합메모리가 허용하면 lance_index_cache_size_bytes를 늘리거나, 불필요한 워밍업을 줄이거나, 별도의 BE 리소스로 워크로드를 격리
스칼라 또는 FTS 쿼리 후 벡터 쿼리가 느려짐공유 캐시 예산 산정의 워크로드 간 캐시 제거 점검을 반복두 쿼리 유형을 함께 고려하여 예산 산정. 동일한 BE에서 Catalog를 분리해도 캐시가 격리되지는 않음
소수의 BE만 대규모 인덱싱 데이터셋을 스캔함물리적 세그먼트 Split 수, 실행 가능한 BE, 스캐너 스케줄링더 많은 균형 잡힌 세그먼트를 비교. 파이프라인 인스턴스만 늘려서는 세그먼트를 분할할 수 없음
세그먼트를 늘리면 CPU, 메모리 또는 병합 시간이 증가함Split별 후보 수, top_k + offset, 쿼리 동시성세그먼트 수를 줄이거나 애플리케이션에 필요한 수보다 많은 후보를 요청하지 않도록 조정. 검색 설정을 변경하면 재현율을 다시 확인
캐시 적중률이 높지만 지연 시간이 계속 김점수 계산, Prefilter 작업, 디코딩, 두 번째 단계의 데이터 가져오기 시간가장 큰 비중을 차지하는 단계를 최적화. 인덱스 캐시를 늘려도 계산이나 데이터 가져오기가 없어지지는 않음
메타데이터 재적재가 지속됨메타데이터 캐시 사용량과 적중/미스 변화량, Fragment/파일 수, 빈번한 버전 변경재사용과 메모리가 허용하면 lance_metadata_cache_size_bytes를 독립적으로 조정
캐시 사용량이 용량보다 낮은데도 프로세스 메모리 사용량이 높음동시 쿼리 할당, 진행 중인 적재, 유지되는 객체, 다른 BE 워크로드측정한 최대 사용량에 따라 동시성이나 캐시 예산을 낮춤. 캐시 용량은 프로세스 메모리의 상한이 아님
데이터 파일 I/O가 계속 높음디스크 캐시 카운터, 재사용, 읽기 블록 크기, 쿼리 출력 컬럼데이터 캐시 예산이나 읽기 단위를 조정. 인덱스 파일은 이 디스크 데이터 캐시를 사용하지 않음

쿼리 Profile 참조를 사용하여 FE 메타데이터/계획 수립, BE 인덱스/스캔 작업, 두 번째 단계의 행 ID 기반 데이터 가져오기를 구분하세요. 캐시 카운터와 BE 전체 메트릭은 캐시 효과 확인을 참고하세요. 전체 적중률만으로는 어떤 인덱스가 제거되었는지, 어느 단계가 지연 시간의 대부분을 차지하는지 알 수 없습니다. 한 번에 하나의 설정만 변경하고, 비교할 때마다 워크로드, 인덱스 버전, BE 배치, 지연 시간, 처리량, 재현율, 최대 메모리 사용량을 기록하세요.