분할된 필드로 최적화된 쿼리

이 페이지에서는 Firestore에서 분할된 필드의 사용량을 보고 제어하는 방법을 설명합니다. 이 기능은 Firestore Enterprise 버전에서 사용할 수 있습니다.

문서가 작성되면 Firestore는 특정 필드를 분할된 형식으로 저장해야 한다고 판단할 수 있습니다. 분할된 필드는 전체 문서 대신 필요한 필드만 읽어 쿼리 성능을 최적화합니다.

분할된 필드의 이점을 활용하는 쿼리

분할된 필드에 대한 읽기는 해당하는 경우 다음 쿼리 형태에 적용됩니다.

  • 집계 쿼리: 집계 작업을 위해 필드의 하위 집합에만 액세스해야 하는 쿼리입니다. 예를 들면 다음과 같습니다.

    db.pipeline()
      .collection("/customers")
      .where(lessThan("account_balance", 0))
      .aggregate(
        countAll().as("total"),
      )
    

    또는 group-by를 사용합니다.

    db.pipeline()
      .collection("/customers")
      .where(lessThan("account_balance", 0))
      .aggregate({
        accumulators: [
          field('account_balance').average().as('avg_account_balance')
        ],
        groups: [field('market_segment')]
      })
    
  • 프로젝션 쿼리: 필드의 특정 하위 집합만 반환하는 쿼리입니다. 예를 들면 다음과 같습니다.

    db.pipeline()
      .collection("/customers")
      .select("family_name", "given_name")
      .limit(10)
    
  • 필터 쿼리: Firestore 쿼리 엔진이 문서 필터링에 분할된 필드를 사용하는 것이 유익하다고 판단하는 쿼리입니다. 예를 들면 다음과 같습니다.

    db.pipeline()
      .collection("/customers")
      .where(equal("given_name", "alice"))
    

분할된 필드 사용량 보기

쿼리 설명을 사용하여 쿼리가 분할된 필드를 사용하는지 확인할 수 있습니다. 쿼리 계획의 TableScan 노드에는 다음 측정항목이 포함된 Storage 섹션이 포함되어 있습니다.

  • 스캔 형태:
    • shredded_fields_only: 쿼리가 분할된 필드에서만 읽습니다.
    • shredded_fields_backjoin: 쿼리가 분할된 필드에서 읽고 다른 필드의 원본 문서와 조인합니다.
  • 사용된 분할된 필드: 분할된 필드로 읽은 필드 이름 목록입니다.
  • 재확인 횟수: 재확인 카운터의 맵입니다. 재확인은 분할된 필드를 스캔할 때 원래 전체 문서에서 읽기로 되돌아가는 것을 의미합니다. 문서의 필드 값이 8KiB를 초과하는 경우 발생할 수 있습니다. 이는 분할된 필드 저장소에 비해 너무 큽니다.

출력 예

...
└── • TableScan
        source: /customers
        order: UNDEFINED
        row range: (-∞..+∞)
        filter: ($account_balance_1 < 0L)
        output bindings: {$account_balance_1=account_balance, $market_segment_1=market_segment}
        variables: [$account_balance_1, $market_segment_1]

        Execution:
         records returned: 1,374
         latency: 26.58 ms
         post-filtered rows: 13,626
         records scanned: 15,000
         data bytes read: 23.73 MiB (24,887,141 B)

        Storage:
         scan shape: shredded_fields_only
         shredded fields used: [account_balance, market_segment]

분할된 필드 사용량 제어

기본적으로 Firestore는 분할된 필드를 사용할 수 있는 경우 이를 사용합니다. table_scan_method 쿼리 옵션을 사용하여 이 동작을 제어할 수 있습니다.

table_scan_method 옵션에 지원되는 값은 다음과 같습니다.

  • shredded_fields_enabled (기본값): 분할된 필드를 사용할 수 있는 경우 이를 사용합니다.
  • shredded_fields_disabled: 분할된 필드를 사용하지 않습니다.
  • force_shredded_fields: 분할된 필드를 스캔하여 테이블 스캔을 완료할 수 없는 경우 쿼리가 실패합니다.

var opts = new PipelineExecuteOptions()
    .with("table_scan_method", "shredded_fields_disabled");

var snapshot = db.pipeline()
    .collection("/customers")
    .where(equal("given_name", "alice"))
    .execute(opts)
    .get();

쿼리 성능 경고

Firestore는 비효율적인 분할된 필드 사용이 감지되면 쿼리 설명 결과에 성능 경고를 표시할 수 있습니다. 예를 들면 다음과 같습니다.

  • 선별성이 낮은 쿼리: 쿼리가 필터링을 위해 분할된 필드를 스캔하지만 필터링되는 문서가 너무 적어 스캔이 비효율적인 경우 발생합니다.

  • 재확인 횟수가 많은 쿼리: 쿼리가 전체 문서 읽기로 자주 되돌아가 성능에 영향을 미칠 수 있는 경우 발생합니다. storage_size와 같은 함수를 사용하여 재확인을 트리거하는 큰 값을 식별할 수 있습니다.

이러한 경우 쿼리 옵션을 사용하여 분할된 필드 읽기를 사용 중지하는 것이 좋습니다.

제한사항

Firestore는 최상위 필드만 분할합니다. 또한 컬렉션 그룹당 분할할 수 있는 필드 수를 제한합니다.