explain 명령

explain 명령

explain 명령은 쿼리의 실행 계획을 표시해요. 쿼리 번역과 문제 해결에 자주 사용돼요. explain 명령은 PPL 쿼리에서 첫 번째 명령으로만 사용할 수 있어요.

출처: 문서

본문

구문(Syntax)

explain 명령은 다음과 같은 구문을 가져요.

explain <mode> queryStatement

매개변수(Parameters)

explain 명령은 다음 매개변수를 지원해요.

Parameter Required/Optional Description
<queryStatement> Required 설명할 PPL 쿼리.
<mode> Optional explain 모드. 유효한 값은 다음과 같아요. - standard: push-down 정보(쿼리 도메인 특화 언어 [DSL])와 함께 논리적 및 물리적 계획을 표시해요. v2와 v3 엔진 모두에서 사용할 수 있어요. - simple: 속성 없이 논리적 계획 트리를 표시해요. v3 엔진(plugins.calcite.enabled=true)이 필요해요. - cost: 표준 정보에 계획 비용 속성을 더해 표시해요. v3 엔진(plugins.calcite.enabled=true)이 필요해요. - extended: 표준 정보에 생성된 코드를 더해 표시해요. 전체 계획이 push-down 가능하면 표준 모드와 동일해요. v3 엔진(plugins.calcite.enabled=true)이 필요해요. 기본값은 standard예요.

예시 1: v2 엔진에서 PPL 쿼리 설명하기

Apache Calcite가 비활성화되면(plugins.calcite.enabled가 false로 설정), explain은 v2 엔진에서 물리적 계획과 push-down 정보를 가져와요.

explain source=state_country
| where country = 'USA' OR country = 'England'
| stats count() by country

이 쿼리는 다음과 같은 결과를 반환해요.

{
  "root": {
    "name": "ProjectOperator",
    "description": {
      "fields": "[count(), country]"
    },
    "children": [
      {
        "name": "OpenSearchIndexScan",
        "description": {
          "request": "\"\"\"OpenSearchQueryRequest(indexName=state_country, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"query\":{\"bool\":{\"should\":[{\"term\":{\"country\":{\"value\":\"USA\",\"boost\":1.0}}},{\"term\":{\"country\":{\"value\":\"England\",\"boost\":1.0}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"country\":{\"terms\":{\"field\":\"country\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"count()\":{\"value_count\":{\"field\":\"_index\"}}}}}}, pitId=null, cursorKeepAlive=null, searchAfter=null, searchResponse=null)\"\"\"
        },
        "children": []
      }
    ]
  }
}

예시 2: v3 엔진에서 PPL 쿼리 설명하기

Apache Calcite가 활성화되면(plugins.calcite.enabled가 true로 설정), explain은 v3 엔진에서 논리적 및 물리적 계획과 push-down 정보를 가져와요.

explain source=state_country
| where country = 'USA' OR country = 'England'
| stats count() by country

이 쿼리는 다음과 같은 결과를 반환해요.

{
  "calcite": {
    "logical": "\"\"\"LogicalProject(count()=[$1], country=[$0])
  LogicalAggregate(group=[{1}], count()=[COUNT()])
    LogicalFilter(condition=[SEARCH($1, Sarg['England', 'USA':CHAR(7)]:CHAR(7))])
      CalciteLogicalIndexScan(table=[[OpenSearch, state_country]])
\"\"\",
    "physical": "\"\"\"EnumerableCalc(expr#0..1=[{inputs}], count()=[$t1], country=[$t0])
  CalciteEnumerableIndexScan(table=[[OpenSearch, state_country]], PushDownContext=[[FILTER->SEARCH($1, Sarg['England', 'USA':CHAR(7)]:CHAR(7)), AGGREGATION->rel#53:LogicalAggregate.NONE.[](https://docs.opensearch.org/latest/sql-and-ppl/ppl/commands/input=RelSubset#43,group={1},count()=COUNT())], OpenSearchRequestBuilder(sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"query\":{\"terms\":{\"country\":[\"England\",\"USA\"],\"boost\":1.0}},\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"country\":{\"terms\":{\"field\":\"country\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"count()\":{\"value_count\":{\"field\":\"_index\"}}}}}}, requestedTotalSize=2147483647, pageSize=null, startFrom=0)])
\"\"\"
  }
}

예시 3: simple 모드에서 PPL 쿼리 설명하기

다음 쿼리는 simple 모드에서 explain 명령을 사용해 단순화된 논리적 계획 트리를 보여줘요.

explain simple source=state_country
| where country = 'USA' OR country = 'England'
| stats count() by country

이 쿼리는 다음과 같은 결과를 반환해요.

{
  "calcite": {
    "logical": "\"\"\"LogicalProject
  LogicalAggregate
    LogicalFilter
      CalciteLogicalIndexScan
\"\"\"
  }
}

예시 4: cost 모드에서 PPL 쿼리 설명하기

다음 쿼리는 cost 모드에서 explain 명령을 사용해 계획 비용 속성을 보여줘요.

explain cost source=state_country
| where country = 'USA' OR country = 'England'
| stats count() by country

이 쿼리는 다음과 같은 결과를 반환해요.

{
  "calcite": {
    "logical": "\"\"\"LogicalProject(count()=[$1], country=[$0]): rowcount = 2.5, cumulative cost = {130.3125 rows, 206.0 cpu, 0.0 io}, id = 75
  LogicalAggregate(group=[{1}], count()=[COUNT()]): rowcount = 2.5, cumulative cost = {127.8125 rows, 201.0 cpu, 0.0 io}, id = 74
    LogicalFilter(condition=[SEARCH($1, Sarg['England', 'USA':CHAR(7)]:CHAR(7))]): rowcount = 25.0, cumulative cost = {125.0 rows, 201.0 cpu, 0.0 io}, id = 73
      CalciteLogicalIndexScan(table=[[OpenSearch, state_country]]): rowcount = 100.0, cumulative cost = {100.0 rows, 101.0 cpu, 0.0 io}, id = 72
\"\"\",
    "physical": "\"\"\"EnumerableCalc(expr#0..1=[{inputs}], count()=[$t1], country=[$t0]): rowcount = 100.0, cumulative cost = {200.0 rows, 501.0 cpu, 0.0 io}, id = 138
  CalciteEnumerableIndexScan(table=[[OpenSearch, state_country]], PushDownContext=[[FILTER->SEARCH($1, Sarg['England', 'USA':CHAR(7)]:CHAR(7)), AGGREGATION->rel#125:LogicalAggregate.NONE.[](https://docs.opensearch.org/latest/sql-and-ppl/ppl/commands/input=RelSubset#115,group={1},count()=COUNT())], OpenSearchRequestBuilder(sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"query\":{\"terms\":{\"country\":[\"England\",\"USA\"],\"boost\":1.0}},\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"country\":{\"terms\":{\"field\":\"country\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"count()\":{\"value_count\":{\"field\":\"_index\"}}}}}}, requestedTotalSize=2147483647, pageSize=null, startFrom=0)]): rowcount = 100.0, cumulative cost = {100.0 rows, 101.0 cpu, 0.0 io}, id = 133
\"\"\"
  }
}

예시 5: extended 모드에서 PPL 쿼리 설명하기

다음 쿼리는 extended 모드에서 explain 명령을 사용해 생성된 코드를 보여줘요.

explain extended source=state_country
| where country = 'USA' OR country = 'England'
| stats count() by country

이 쿼리는 다음과 같은 결과를 반환해요.

{
  "calcite": {
    "logical": "\"\"\"LogicalProject(count()=[$1], country=[$0])
  LogicalAggregate(group=[{1}], count()=[COUNT()])
    LogicalFilter(condition=[SEARCH($1, Sarg['England', 'USA':CHAR(7)]:CHAR(7))])
      CalciteLogicalIndexScan(table=[[OpenSearch, state_country]])
\"\"\",
    "physical": "\"\"\"EnumerableCalc(expr#0..1=[{inputs}], count()=[$t1], country=[$t0])
  CalciteEnumerableIndexScan(table=[[OpenSearch, state_country]], PushDownContext=[[FILTER->SEARCH($1, Sarg['England', 'USA':CHAR(7)]:CHAR(7)), AGGREGATION->rel#193:LogicalAggregate.NONE.[](https://docs.opensearch.org/latest/sql-and-ppl/ppl/commands/input=RelSubset#183,group={1},count()=COUNT())], OpenSearchRequestBuilder(sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"query\":{\"terms\":{\"country\":[\"England\",\"USA\"],\"boost\":1.0}},\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"country\":{\"terms\":{\"field\":\"country\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"count()\":{\"value_count\":{\"field\":\"_index\"}}}}}}, requestedTotalSize=2147483647, pageSize=null, startFrom=0)])
\"\"\",
    "extended": "\"\"\"public org.apache.calcite.linq4j.Enumerable bind(final org.apache.calcite.DataContext root) {
  final org.opensearch.sql.opensearch.storage.scan.CalciteEnumerableIndexScan v1stashed = (org.opensearch.sql.opensearch.storage.scan.CalciteEnumerableIndexScan) root.get(\"v1stashed\");
  final org.apache.calcite.linq4j.Enumerable _inputEnumerable = v1stashed.scan();
  return new org.apache.calcite.linq4j.AbstractEnumerable(){
      public org.apache.calcite.linq4j.Enumerator enumerator() {
        return new org.apache.calcite.linq4j.Enumerator(){
            public final org.apache.calcite.linq4j.Enumerator inputEnumerator = _inputEnumerable.enumerator();
            public void reset() {
              inputEnumerator.reset();
            }
            public boolean moveNext() {
              return inputEnumerator.moveNext();
            }
            public void close() {
              inputEnumerator.close();
            }
            public Object current() {
              final Object[] current = (Object[]) inputEnumerator.current();
              final Object input_value = current[1];
              final Object input_value0 = current[0];
              return new Object[] {
                  input_value,
                  input_value0};
            }
          };
      }
    };
}
public Class getElementType() {
  return java.lang.Object[].class;
}
\"\"\"
  }
}

더 알아보기 (Learn more)