쿼리 계획 및 타임라인

쿼리 작업 내에 삽입된 BigQuery에는 진단 쿼리 계획과 타이밍 정보가 포함되어 있습니다. 이는 다른 데이터베이스 및 분석 시스템에서 EXPLAIN과 같은 문으로 제공되는 정보와 유사합니다. 이 정보는 jobs.get과 같은 메소드의 API 응답에서 가져올 수 있습니다.

장기간 실행 중인 쿼리의 경우 BigQuery는 통계를 주기적으로 업데이트합니다. 이러한 업데이트는 작업 상태가 폴링되는 비율과 상관없이 진행되지만 일반적으로 최소 주기는 30초입니다. 또한 실행 리소스를 활용하지 않는 쿼리 작업(예: 테스트 실행 요청, 캐시된 결과에서 제공할 수 있는 결과)에는 다른 통계가 있을 수 있지만 추가 진단 정보는 포함되지 않습니다.

배경

BigQuery는 쿼리 작업 실행 시 선언적 SQL 문을 실행 그래프로 변환하고 일련의 쿼리 스테이지로 세분화합니다. 각 쿼리 스테이지에는 더 세분화된 실행 단계 조합이 있습니다. BigQuery는 크게 분산된 병렬 아키텍처를 사용하여 이러한 쿼리를 실행하며, 스테이지는 많은 잠재적 작업자들이 동시에 실행할 수 있는 작업 단위를 모델링합니다. 스테이지는 빠른 분산 셔플 아키텍처를 통해 서로 간에 통신하여, 자세한 내용은 다른 문서에서 설명합니다.

쿼리 계획 내에서 작업 단위 및 작업자 조건이 사용됩니다. 이는 계획이 동시 로드 정보를 구체적으로 전달하기 때문입니다. BigQuery 내의 다른 곳에서는 컴퓨팅, 메모리, I/O 리소스를 비롯한 쿼리 실행의 여러 측면을 추상화한 '슬롯'이라는 용어를 볼 수 있습니다. 최상위 작업 통계는 이 추상화된 계정을 통해 쿼리의 totalSlotMs 추정을 사용함으로써 개별 쿼리 비용의 추정치를 제공합니다.

쿼리 실행 아키텍처의 또 다른 중요한 속성은 동적이라는 것입니다. 즉, 쿼리가 실행되는 동안 쿼리 계획이 수정될 수 있습니다. 쿼리가 실행 중인 동안에 스테이지를 도입하는 목적은 쿼리 작업자 전체의 데이터 배포를 향상시키기 위한 경우가 많습니다. 실제로 이러한 쿼리 계획에는 일반적으로 Repartition 스테이지라는 라벨이 지정됩니다.

쿼리 계획 외에도 쿼리 작업에는 쿼리 작업자 사이에서 완료, 보류, 활성 상태의 작업 단위에 대한 설명을 제공하는 실행 타임라인이 노출됩니다. 쿼리에는 활성 작업자를 포함한 여러 스테이지가 동시에 있을 수 있으므로, 타임라인은 쿼리의 전반적인 진행 상황을 보여주기 위한 것입니다.

기본 BigQuery 웹 UI로 정보 보기

기본 BigQuery 웹 UI를 사용하면 결과 버튼 오른쪽에 있는 세부정보 버튼을 클릭하여 완료된 쿼리에 대한 쿼리 계획의 세부정보를 볼 수 있습니다.

쿼리 계획 스크린샷

장기 실행 중인 쿼리의 경우, 쿼리 작성기 창 아래의 쿼리 상태 표시줄에 있는 링크를 클릭하여 진행 중인 쿼리 계획을 볼 수 있습니다.

경과 시간 상태 표시줄 스크린샷

쿼리 계획 정보

API 응답 내에서 쿼리 계획은 스테이지별 개요 통계, 세부 단계 정보, 스테이지 타이밍 분류를 보여주는 쿼리 스테이지 목록으로 표시됩니다. 웹 UI에 모든 세부정보가 표시되지는 않지만 API 응답 내에 정보가 있을 수 있습니다.

스테이지 개요

각 스테이지의 개요 필드에 포함될 수 있는 항목은 다음과 같습니다.

API 필드 설명
id 스테이지의 고유 숫자 ID입니다.
name 스테이지의 간단한 요약 이름입니다. 스테이지 내의 steps는 실행 단계에 대한 추가 세부정보를 제공합니다.
status 스테이지의 실행 상태입니다. 가능한 상태로는 PENDING, RUNNING, COMPLETE, FAILED, CANCELLED가 있습니다.
inputStages 스테이지의 종속성 그래프를 구성하는 ID 목록입니다. 예를 들어 JOIN 스테이지에는 주로 JOIN 관계의 왼쪽과 오른쪽에서 데이터를 준비하는 독립 스테이지 2개가 필요합니다.
startMs 스테이지 내에서 첫 작업자가 실행을 시작한 시간을 나타내는 이폭 밀리초 단위의 타임스탬프입니다.
endMs 마지막 작업자가 실행을 완료한 시간을 나타내는 이폭 밀리초 단위의 타임스탬프입니다.
steps 스테이지 내의 세부적인 실행 단계 목록입니다. 자세한 내용은 다음 섹션을 참조하세요.
recordsRead 모든 스테이지 작업자에 대한 레코드 수 기준의 스테이지 입력 크기입니다.
recordsWritten 모든 스테이지 작업자에 대한 레코드 수 기준의 스테이지 출력 크기입니다.
parallelInputs 스테이지에서 동시 로드가 가능한 작업 단위 수입니다. 스테이지와 쿼리에 따라 테이블 내에서 열 세그먼트의 수 또는 중간 셔플 내 파티션 수를 나타낼 수 있습니다.
completedParallelInputs 완료된 스테이지 내의 작업 단위 수입니다. 일부 쿼리의 경우 스테이지 내 일부 입력을 완료하지 않아도 스테이지가 완료될 수 있습니다.
shuffleOutputBytes 쿼리 스테이지 내 모든 작업자에 대한 총 바이트 수를 나타냅니다.
shuffleOutputBytesSpilled 스테이지 간에 중요한 데이터를 전송하는 쿼리를 디스크 기반 전송으로 대체해야 할 수도 있습니다. 분산된 바이트 통계는 디스크로 분산된 데이터의 양을 알려줍니다.

스테이지별 단계 정보

단계는 스테이지 내에서 각 작업자가 실행해야 하는 더욱 세분화된 작업을 나타내며 정렬된 작업 목록으로 제공됩니다. 단계는 카테고리화되며 일부 작업은 보다 세부적인 정보를 제공합니다. 쿼리 계획의 작업 카테고리는 다음과 같습니다.

단계 설명
READ 입력 테이블 또는 중간 셔플에서 열 한 개 이상 읽기
WRITE 출력 테이블 또는 중간 결과에 열 한 개 이상 쓰기. 스테이지에서 HASH 파티션을 나눈 출력의 경우, 파티션 키에 사용된 열도 포함됩니다.
COMPUTE 표현식 평가 및 SQL 함수와 같은 연산
FILTER WHERE, OMIT IF, HAVING 절을 구현하는 연산자
SORT 정렬 또는 정렬 기준 연산. 열 키와 방향이 포함됩니다.
AGGREGATE GROUP BY 또는 COUNT 등의 집계 연산
LIMIT LIMIT 절을 구현하는 연산자
JOIN 사용된 조인 유형과 열을 포함한 JOIN 연산자
ANALYTIC_FUNCTION 분석 함수('윈도우 함수'라고도 함) 호출
USER_DEFINED_FUNCTION 사용자 정의 함수 호출

스테이지별 타이밍 분류

쿼리 스테이지는 상대적 형태와 절대적 형태로 스테이지 타이밍 분류도 제공합니다. 각 실행 스테이지는 독립 작업자 1명 이상이 수행한 작업을 나타내므로, 평균 시간과 가장 느린 시간으로 정보가 제공됩니다. 즉, 스테이지의 모든 작업자에 대한 평균 성과와 지정된 분류에서 가장 시간이 오래 걸린 작업자의 성과가 표시됩니다. 평균 및 최대 시간은 절대 표시와 상대 표시로 더 세분화됩니다. 비율 기반 통계의 경우 임의의 세그먼트에 있는 작업자 중 가장 시간이 오래 걸린 작업자가 소비한 시간의 비율로 데이터가 제공됩니다.

기본 BigQuery 웹 UI는 상대적 타이밍 표현을 사용하여 스테이지 타이밍을 표시합니다.

스테이지 타이밍 정보는 다음과 같이 보고됩니다.

상대적 타이밍 절대적 타이밍 기본 BigQuery 웹 UI* 비율 분자**
waitRatioAvg waitMsAvg waitRatioAvg 짙은 노란색 막대 평균 작업자가 예약되기 위해 대기한 시간입니다.
waitRatioMax waitMsMax waitRatioMax 노란색 막대 가장 시간이 오래 걸린 작업자가 예약되기 위해 대기한 시간입니다.
readRatioAvg readMsAvg readRatioAvg 짙은 보라색 막대 평균 작업자가 입력 데이터를 읽는 데 걸린 시간입니다.
readRatioMax readMsMax readRatioMax 보라색 막대 가장 시간이 오래 걸린 작업자가 입력 데이터를 읽는 데 걸린 시간입니다.
computeRatioAvg computeMsAvg computeRatioAvg 짙은 주황색 막대 평균 작업자가 CPU의 제한을 받은 시간입니다.
computeRatioMax computeMsMax computeRatioMax 주황색 막대 가장 시간이 오래 걸린 작업자가 CPU의 제한을 받은 시간입니다.
writeRatioAvg writeMsAvg writeRatioAvg 짙은 파란색 막대 평균 작업자가 출력 데이터를 쓰는 데 걸린 시간입니다.
writeRatioMax writeMsMax writeRatioMax 파란색 막대 가장 시간이 오래 걸린 작업자가 출력 데이터를 쓰는 데 걸린 시간입니다.

* 'AVG'와 'MAX' 라벨은 예시용이며 기본 BigQuery 웹 UI에는 나타나지 않습니다.

타임라인 메타데이터

쿼리 타임라인은 특정 시점에서 진행 상황을 보고하여 전체 쿼리 진행의 스냅샷 보기를 제공합니다. 타임라인은 다음 세부정보를 보고하는 일련의 샘플로 표시됩니다.

필드 설명
elapsedMs 쿼리 실행이 시작된 후 경과된 시간(밀리초 단위)
totalSlotMs 쿼리에서 사용된 슬롯-밀리초 누적 표시
pendingUnits 예약 작업 및 실행 대기 중인 작업의 총 단위
activeUnits 현재 작업자가 처리 중인 총 활성 작업 단위
completedUnits 이 쿼리를 실행하는 동안 완료된 총 작업 단위

예시 쿼리

셰익스피어 공개 데이터 세트에서 행 수를 계산하는 간단한 쿼리와 햄릿을 참조하는 행으로 결과를 제한하는 두 번째 조건부 계수를 실행하는 경우:

#StandardSQL
SELECT
  COUNT(1) as rowcount,
  COUNTIF(corpus = 'hamlet') as rowcount_hamlet
FROM `publicdata.samples.shakespeare`

세부정보를 클릭하여 쿼리 계획에 대한 다음 정보를 확인할 수 있습니다. 먼저 쿼리 타임라인이 포함된 첫 번째 섹션을 살펴보겠습니다.

햄릿 쿼리 타임라인 스크린샷

이 예에서는 매우 작은 샘플 테이블과 간단한 쿼리를 다루기 때문에 총 작업 단위가 2개만 있습니다. 모든 작업은 거의 즉시 완료됩니다.

그러면 우선 쿼리 계획을 살펴보겠습니다.

햄릿 쿼리 계획 스크린샷

이 예에서 색상 표시기는 모든 스테이지의 상대적 타이밍을 나타냅니다. 병렬 입력 정보를 보면 각 스테이지에 단일 작업자만 필요하다는 것을 알 수 있습니다. 따라서 평균 타이밍과 가장 느린 타이밍 사이에 변동이 없습니다.

또한 이 간단한 쿼리의 경우, 세그먼트에서 가장 긴 시간은 스테이지 01에 있는 단일 작업자가 스테이지 00이 완료되기를 기다리는 시간이었음을 알 수 있습니다. 그 이유는 스테이지 01이 스테이지 00 입력에 종속되어 있고 첫 번째 스테이지가 중간 셔플에 출력(1행, 약 18바이트)을 쓰기 전까지 시작될 수 없기 때문입니다.

이제 실행 스테이지의 단계를 살펴보겠습니다. 스테이지 라벨 왼쪽에서 삼각형을 클릭하여 스테이지 세부정보를 확장합니다.

햄릿 쿼리 계획의 단계 세부정보 스크린샷

이 경우, 스테이지 00 작업을 완료한 단일 작업자에 대한 실행 계획을 볼 수 있습니다. 먼저 참조된 셰익스피어 테이블의 'corpus' 열에서 데이터가 읽혔습니다. 그 다음 COUNTCOUNTIF 프로젝션에 대해 AGGREGATIONS가 설정되었습니다. 데이터를 스캔하려면 COMPUTE 단계가 필요했는데, 이 단계에서는 정상 및 조건 개수에 대한 데이터가 제공되었으며 출력은 이 계획에서 __stage00_output 라벨이 지정된 중간 셔플 출력에 기록되었습니다.

오류 보고

쿼리 작업이 실행 중간에 실패할 수 있습니다. 계획 정보가 주기적으로 업데이트되므로, 실행 그래프에서 오류가 발생한 위치를 관찰할 수 있습니다. UI 내에서 성공한 스테이지와 실패한 스테이지는 스테이지 이름 옆에 확인 표시와 느낌표로 표시됩니다.

오류 해석 및 해결에 대한 자세한 내용은 문제해결 가이드를 참조하세요.

API 샘플 표현

쿼리 계획 정보는 메소드를 추가로 호출할 필요 없이 작업 응답 정보에 자동으로 삽입되며 간단히 jobs.get을 호출하여 작업 세부정보를 가져오는 방식으로 검색할 수 있습니다. 예를 들어 다음은 쿼리 계획과 타임라인 정보를 보여주는 샘플 햄릿 쿼리를 반환하는 작업에 대한 JSON 응답의 일부입니다.

"statistics": {
  "query": {
    "cacheHit": false,
    "queryPlan": [
      {
        "completedParallelInputs": "1",
        "computeMsAvg": "25",
        "computeMsMax": "25",
        "computeRatioAvg": 0.17857142857142858,
        "computeRatioMax": 0.17857142857142858,
        "endMs": "1522787349945",
        "id": "0",
        "name": "S00: Input",
        "parallelInputs": "1",
        "readMsAvg": "28",
        "readMsMax": "28",
        "readRatioAvg": 0.2,
        "readRatioMax": 0.2,
        "recordsRead": "164656",
        "recordsWritten": "1",
        "shuffleOutputBytes": "18",
        "shuffleOutputBytesSpilled": "0",
        "startMs": "1522787349898",
        "status": "COMPLETE",
        "steps": [
          {
            "kind": "READ",
            "substeps": [
              "$1:corpus",
              "FROM publicdata.samples.shakespeare"
            ]
          },
          {
            "kind": "AGGREGATE",
            "substeps": [
              "$20 := COUNT($30)",
              "$21 := COUNTIF($31)"
            ]
          },
          {
            "kind": "COMPUTE",
            "substeps": [
              "$30 := 1",
              "$31 := equal($1, 'hamlet')"
            ]
          },
          {
            "kind": "WRITE",
            "substeps": [
              "$20, $21",
              "TO __stage00_output"
            ]
          }
        ],
        "waitMsAvg": "0",
        "waitMsMax": "0",
        "waitRatioAvg": 0.0,
        "waitRatioMax": 0.0,
        "writeMsAvg": "5",
        "writeMsMax": "5",
        "writeRatioAvg": 0.03571428571428571,
        "writeRatioMax": 0.03571428571428571
      },
      {
        "completedParallelInputs": "1",
        "computeMsAvg": "14",
        "computeMsMax": "14",
        "computeRatioAvg": 0.1,
        "computeRatioMax": 0.1,
        "endMs": "1522787350180",
        "id": "1",
        "inputStages": [
          "0"
        ],
        "name": "S01: Output",
        "parallelInputs": "1",
        "readMsAvg": "0",
        "readMsMax": "0",
        "readRatioAvg": 0.0,
        "readRatioMax": 0.0,
        "recordsRead": "1",
        "recordsWritten": "1",
        "shuffleOutputBytes": "16",
        "shuffleOutputBytesSpilled": "0",
        "startMs": "1522787350038",
        "status": "COMPLETE",
        "steps": [
          {
            "kind": "READ",
            "substeps": [
              "$20, $21",
              "FROM __stage00_output"
            ]
          },
          {
            "kind": "AGGREGATE",
            "substeps": [
              "$10 := SUM_OF_COUNTS($20)",
              "$11 := SUM_OF_COUNTS($21)"
            ]
          },
          {
            "kind": "WRITE",
            "substeps": [
              "$10, $11",
              "TO __stage01_output"
            ]
          }
        ],
        "waitMsAvg": "140",
        "waitMsMax": "140",
        "waitRatioAvg": 1.0,
        "waitRatioMax": 1.0,
        "writeMsAvg": "129",
        "writeMsMax": "129",
        "writeRatioAvg": 0.9214285714285714,
        "writeRatioMax": 0.9214285714285714
      }
    ],
    "referencedTables": [
      {
        "datasetId": "samples",
        "projectId": "publicdata",
        "tableId": "shakespeare"
      }
    ],
    "statementType": "SELECT",
    "timeline": [
      {
        "activeUnits": "0",
        "completedUnits": "2",
        "elapsedMs": "999",
        "pendingUnits": "0",
        "totalSlotMs": "185"
      },
      {
        "activeUnits": "0",
        "completedUnits": "2",
        "elapsedMs": "1197",
        "pendingUnits": "0",
        "totalSlotMs": "185"
      }
    ],
    "totalBytesBilled": "10485760",
    "totalBytesProcessed": "2464625",
    "totalPartitionsProcessed": "0",
    "totalSlotMs": "127"
  },
  "totalBytesProcessed": "2464625"
},

실행 정보 사용

BigQuery 쿼리 계획은 서비스에서 쿼리가 실행되는 방식에 대한 정보를 제공하지만 서비스의 관리 특성으로 인해 일부 세부정보의 직접적인 조치 가능 여부에는 제한이 있습니다. 미세 조정, 프로비저닝, 모니터링에 지식이 풍부한 전문 직원이 필요할 수 있는 다른 환경과 달리, 이 서비스를 사용하면 많은 최적화가 자동으로 수행됩니다.

쿼리 실행과 성능을 향상시킬 수 있는 특정 기술에 대해서는 권장사항 문서를 참조하세요. 쿼리 계획과 타임라인 통계는 어떤 스테이지에 리소스 사용이 집중되는지 이해하는 데 유용할 수 있습니다. 예를 들어, 입력 행보다 훨씬 많은 출력 행을 생성하는 JOIN 스테이지는 쿼리에서 일찍 필터링하는 것이 좋을 수 있음을 나타냅니다.

또한 타임라인 정보는 지정된 쿼리가 독립적인 상태에서 느린 것인지 또는 같은 리소스를 놓고 경합하는 다른 쿼리의 영향으로 인해 느린 것인지 식별하는 데 유용할 수 있습니다. 활성 단위 수가 쿼리 수명 동안 제한적이지만 대기 중인 작업 단위 수는 높게 유지되는 경우, 동시 쿼리 수를 줄여 특정 쿼리에 대한 전반적인 실행 시간을 크게 향상시킬 수 있음을 나타냅니다.

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...

도움이 필요하시나요? 지원 페이지를 방문하세요.