쿼리 최적화 도구 관리

Cloud Spanner는 쿼리 최적화 도구 버전 관리를 통해 옵티마이저 제어를 제공합니다. 이 가이드에서는 쿼리에서 사용하는 쿼리 최적화 도구 버전을 관리하는 방법을 설명합니다.

Cloud Spanner의 쿼리 최적화 도구에 대한 업데이트를 출시하면서 목표는 쿼리 실행 계획을 개선하고 쿼리 성능을 개선하는 것입니다. 기본적으로 Cloud Spanner는 각 데이터베이스에 최신 쿼리 최적화 도구 버전을 사용합니다. 쿼리 최적화 도구 버전을 관리하면 예측 가능한 성능을 제공하는 이전 버전의 최적화 도구에 대해 쿼리를 실행할 수 있습니다.

지원되는 최적화 도구 버전 나열

쿼리 최적화 도구 버전은 정수 값이며, 각 업데이트마다 1씩 증가합니다. 쿼리 최적화 도구의 최신 버전은 2입니다.

다음 SQL 문을 실행하여 지원되는 모든 최적화 도구 버전의 목록과 해당 버전의 출시 날짜를 반환합니다. 반환되는 값 중 가장 큰 버전 번호는 지원되는 최신 버전입니다.

SELECT * FROM SPANNER_SYS.SUPPORTED_OPTIMIZER_VERSIONS

기본적으로 Cloud Spanner는 최신 버전의 최적화 도구(현재는 2)를 사용합니다. 이 가이드에 설명된 방법 중 하나를 사용하여 시나리오의 기본 동작을 재정의합니다.

각 버전에 대한 자세한 내용은 쿼리 최적화 도구 버전 기록을 참조하세요.

버전 재정의 우선순위

Cloud Spanner는 최적화 도구 버전을 변경하는 다양한 방법을 제공합니다. 예를 들어 특정 쿼리의 버전을 설정하거나 클라이언트 라이브러리에서 프로세스 또는 쿼리 수준으로 버전을 구성할 수 있습니다. 버전이 여러 방식으로 설정된 경우 다음 우선순위 순서가 적용됩니다. 이 문서의 해당 섹션으로 이동하려면 링크를 선택하세요.

Cloud Spanner 기본 ← 데이터베이스 옵션클라이언트 앱환경 변수클라이언트 쿼리문 힌트

위의 우선순위 순서를 다음과 같이 해석할 수 있습니다. 데이터베이스를 만들면 항상 최신 버전인 Cloud Spanner 기본 최적화 도구 버전이 사용됩니다. 위에 나열된 방법 중 하나를 사용하여 최적화 도구 버전을 설정하면 선택한 방법은 왼쪽에 있는 모든 항목보다 우선합니다. 예를 들어 환경 변수를 사용하여 앱의 최적화 도구를 설정하면 이는 데이터베이스 옵션을 사용하여 데이터베이스에 설정한 값보다 우선합니다. 문 힌트를 통해 최적화 도구 버전을 설정하면 다른 방법을 사용하여 설정된 값보다 해당 쿼리에 대해 높은 우선순위를 갖습니다.

이제 각 방법을 살펴보겠습니다.

ALTER DATABASE를 사용하여 데이터베이스의 최적화 도구 버전 설정

다음과 같은 ALTER DATABASE DDL 명령어를 사용하여 데이터베이스에 기본 최적화 도구 버전을 설정할 수 있습니다.

ALTER DATABASE MyDatabase
SET OPTIONS (optimizer_version = 2);

다음과 같이 gcloud spanner databases ddl update 명령어를 사용하여 gcloud spanner에서 ALTER DATABASE를 실행할 수 있습니다.

gcloud spanner databases ddl update MyDatabase --instance=test-instance \
    --ddl='ALTER DATABASE MyDatabase SET OPTIONS ( optimizer_version = 2 )'

데이터베이스 옵션을 NULL로 설정하면 데이터베이스 기본값을 최신 버전으로 설정합니다. 이는 새 데이터베이스의 기본값입니다.

데이터베이스에 대한 이 옵션의 현재 값을 보려면 INFORMATION_SCHEMA.DATABASE_OPTIONS 보기를 확인합니다.

클라이언트 앱의 최적화 도구 버전 설정

클라이언트 라이브러리를 통해 프로그래매틱 방식으로 Cloud Spanner와 상호 작용하는 경우 다양한 방법으로 클라이언트 애플리케이션의 최적화 도구 버전을 변경할 수 있습니다.

애플리케이션은 쿼리 옵션 속성을 다음 코드 스니펫과 같이 구성하여 클라이언트 라이브러리에서 전역 쿼리 옵션을 설정할 수 있습니다. 최적화 도구 버전 설정은 클라이언트 인스턴스에 저장되며 클라이언트의 수명 동안 실행되는 모든 쿼리에 적용됩니다. 옵션은 백엔드의 데이터베이스 수준에서 적용되지만 클라이언트 수준으로 설정되면 해당 클라이언트를 통해 연결된 모든 데이터베이스에 적용됩니다.

C++

namespace spanner = ::google::cloud::spanner;
spanner::Client client(
    spanner::MakeConnection(db),
    spanner::ClientOptions().set_query_options(
        spanner::QueryOptions().set_optimizer_version("1")));

C#

var builder = new SpannerConnectionStringBuilder
{
    DataSource = $"projects/{projectId}/instances/{instanceId}/databases/{databaseId}"
};
// Create connection to Cloud Spanner.
using (var connection = new SpannerConnection(builder))
{
    // Set query options on the connection.
    connection.QueryOptions = QueryOptions.Empty.WithOptimizerVersion("1");
    var cmd = connection.CreateSelectCommand(
        "SELECT SingerId, AlbumId, AlbumTitle FROM Albums");
    using (var reader = await cmd.ExecuteReaderAsync())
    {
        while (await reader.ReadAsync())
        {
            Console.WriteLine("SingerId : "
            + reader.GetFieldValue<string>("SingerId")
            + " AlbumId : "
            + reader.GetFieldValue<string>("AlbumId")
            + " AlbumTitle : "
            + reader.GetFieldValue<string>("AlbumTitle"));
        }
    }
}

Go


import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/spanner"
	"google.golang.org/api/iterator"
	sppb "google.golang.org/genproto/googleapis/spanner/v1"
)

func createClientWithQueryOptions(w io.Writer, database string) error {
	ctx := context.Background()
	queryOptions := spanner.QueryOptions{
		Options: &sppb.ExecuteSqlRequest_QueryOptions{OptimizerVersion: "1"},
	}
	client, err := spanner.NewClientWithConfig(
		ctx, database, spanner.ClientConfig{QueryOptions: queryOptions},
	)
	if err != nil {
		return err
	}
	defer client.Close()

	stmt := spanner.Statement{SQL: `SELECT VenueId, VenueName, LastUpdateTime FROM Venues`}
	iter := client.Single().Query(ctx, stmt)
	defer iter.Stop()
	for {
		row, err := iter.Next()
		if err == iterator.Done {
			return nil
		}
		if err != nil {
			return err
		}
		var venueID int64
		var venueName string
		var lastUpdateTime time.Time
		if err := row.Columns(&venueID, &venueName, &lastUpdateTime); err != nil {
			return err
		}
		fmt.Fprintf(w, "%d %s %s\n", venueID, venueName, lastUpdateTime)
	}
}

자바

static void clientWithQueryOptions(DatabaseId db) {
  SpannerOptions options =
      SpannerOptions.newBuilder()
          .setDefaultQueryOptions(
              db, QueryOptions.newBuilder().setOptimizerVersion("1").build())
          .build();
  Spanner spanner = options.getService();
  DatabaseClient dbClient = spanner.getDatabaseClient(db);
  try (ResultSet resultSet =
      dbClient
          .singleUse()
          .executeQuery(Statement.of("SELECT SingerId, AlbumId, AlbumTitle FROM Albums"))) {
    while (resultSet.next()) {
      System.out.printf(
          "%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1), resultSet.getString(2));
    }
  }
}

Node.js

// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId, {}, {optimizerVersion: '1'});

const query = {
  sql: `SELECT AlbumId, AlbumTitle, MarketingBudget
        FROM Albums
        ORDER BY AlbumTitle`,
};

// Queries rows from the Albums table
try {
  const [rows] = await database.run(query);

  rows.forEach(row => {
    const json = row.toJSON();
    const marketingBudget = json.MarketingBudget
      ? json.MarketingBudget
      : null; // This value is nullable
    console.log(
      `AlbumId: ${json.AlbumId}, AlbumTitle: ${json.AlbumTitle}, MarketingBudget: ${marketingBudget}`
    );
  });
} catch (err) {
  console.error('ERROR:', err);
} finally {
  // Close the database when finished.
  database.close();
}

PHP

use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Database;

/**
 * Create a client with query options.
 * Example:
 * ```
 * create_client_with_query_options($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function create_client_with_query_options($instanceId, $databaseId)
{
    $spanner = new SpannerClient([
        'queryOptions' => [
            'optimizerVersion' => "1"
        ]
    ]);
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $results = $database->execute(
        'SELECT VenueId, VenueName, LastUpdateTime FROM Venues'
    );

    foreach ($results as $row) {
        printf('VenueId: %s, VenueName: %s, LastUpdateTime: %s' . PHP_EOL,
            $row['VenueId'], $row['VenueName'], $row['LastUpdateTime']);
    }
}

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
spanner_client = spanner.Client(query_options={"optimizer_version": "1"})
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

with database.snapshot() as snapshot:
    results = snapshot.execute_sql(
        "SELECT VenueId, VenueName, LastUpdateTime FROM Venues"
    )

    for row in results:
        print(u"VenueId: {}, VenueName: {}, LastUpdateTime: {}".format(*row))

Ruby

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"

require "google/cloud/spanner"

query_options = { optimizer_version: "1" }

spanner = Google::Cloud::Spanner.new project: project_id
client  = spanner.client instance_id, database_id, query_options: query_options

sql_query = "SELECT VenueId, VenueName, LastUpdateTime FROM Venues"

client.execute(sql_query).rows.each do |row|
  puts "#{row[:VenueId]} #{row[:VenueName]} #{row[:LastUpdateTime]}"
end

환경 변수를 사용하여 클라이언트 앱의 최적화 도구 버전 설정

앱을 다시 컴파일하지 않고도 다양한 최적화 도구 버전을 더 쉽게 사용하려면 다음 스니펫과 같이 SPANNER_OPTIMIZER_VERSION 환경 변수를 설정하고 앱을 실행합니다.

Linux/macOS

export SPANNER_OPTIMIZER_VERSION="2"

Windows

set SPANNER_OPTIMIZER_VERSION="2"

지정된 쿼리 최적화 도구 버전 값은 클라이언트를 초기화할 때 읽고 클라이언트 인스턴스에 저장되며 클라이언트 수명 동안 실행되는 모든 쿼리에 적용됩니다.

클라이언트 쿼리의 최적화 도구 버전 설정

쿼리를 빌드할 때 쿼리 옵션 속성을 지정하여 클라이언트 애플리케이션의 쿼리 수준에서 최적화 도구 버전의 값을 지정할 수 있습니다. 아래의 지원되는 각 언어에 대한 코드 스니펫에 표시되어 있습니다.

C++

void QueryWithQueryOptions(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;
  auto sql = spanner::SqlStatement("SELECT SingerId, FirstName FROM Singers");
  auto opts = spanner::QueryOptions().set_optimizer_version("1");
  auto rows = client.ExecuteQuery(std::move(sql), std::move(opts));

  using RowType = std::tuple<std::int64_t, std::string>;
  for (auto const& row : spanner::StreamOf<RowType>(rows)) {
    if (!row) throw std::runtime_error(row.status().message());
    std::cout << "SingerId: " << std::get<0>(*row) << "\t";
    std::cout << "FirstName: " << std::get<1>(*row) << "\n";
  }
  std::cout << "Read completed for [spanner_query_with_query_options]\n";
}

C#

var builder = new SpannerConnectionStringBuilder
{
    DataSource = $"projects/{projectId}/instances/{instanceId}/databases/{databaseId}"
};
// Create connection to Cloud Spanner.
using (var connection = new SpannerConnection(builder))
{
    var cmd = connection.CreateSelectCommand(
        "SELECT SingerId, AlbumId, AlbumTitle FROM Albums");
    // Set query options just for this command.
    cmd.QueryOptions = QueryOptions.Empty.WithOptimizerVersion("1");
    using (var reader = await cmd.ExecuteReaderAsync())
    {
        while (await reader.ReadAsync())
        {
            Console.WriteLine("SingerId : "
            + reader.GetFieldValue<string>("SingerId")
            + " AlbumId : "
            + reader.GetFieldValue<string>("AlbumId")
            + " AlbumTitle : "
            + reader.GetFieldValue<string>("AlbumTitle"));
        }
    }
}

Go


import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/spanner"
	"google.golang.org/api/iterator"
	sppb "google.golang.org/genproto/googleapis/spanner/v1"
)

func queryWithQueryOptions(w io.Writer, db string) error {
	ctx := context.Background()
	client, err := spanner.NewClient(ctx, db)
	if err != nil {
		return err
	}
	defer client.Close()

	stmt := spanner.Statement{SQL: `SELECT VenueId, VenueName, LastUpdateTime FROM Venues`}
	queryOptions := spanner.QueryOptions{
		Options: &sppb.ExecuteSqlRequest_QueryOptions{OptimizerVersion: "1"},
	}
	iter := client.Single().QueryWithOptions(ctx, stmt, queryOptions)
	defer iter.Stop()
	for {
		row, err := iter.Next()
		if err == iterator.Done {
			return nil
		}
		if err != nil {
			return err
		}
		var venueID int64
		var venueName string
		var lastUpdateTime time.Time
		if err := row.Columns(&venueID, &venueName, &lastUpdateTime); err != nil {
			return err
		}
		fmt.Fprintf(w, "%d %s %s\n", venueID, venueName, lastUpdateTime)
	}
}

자바

static void queryWithQueryOptions(DatabaseClient dbClient) {
  try (ResultSet resultSet =
      dbClient
          .singleUse()
          .executeQuery(
              Statement
                  .newBuilder("SELECT SingerId, AlbumId, AlbumTitle FROM Albums")
                  .withQueryOptions(QueryOptions.newBuilder().setOptimizerVersion("1").build())
                  .build())) {
    while (resultSet.next()) {
      System.out.printf(
          "%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1), resultSet.getString(2));
    }
  }
}

Node.js

// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);

const query = {
  sql: `SELECT AlbumId, AlbumTitle, MarketingBudget
        FROM Albums
        ORDER BY AlbumTitle`,
  queryOptions: {
    optimizerVersion: 'latest',
  },
};

// Queries rows from the Albums table
try {
  const [rows] = await database.run(query);

  rows.forEach(row => {
    const json = row.toJSON();
    const marketingBudget = json.MarketingBudget
      ? json.MarketingBudget
      : null; // This value is nullable
    console.log(
      `AlbumId: ${json.AlbumId}, AlbumTitle: ${json.AlbumTitle}, MarketingBudget: ${marketingBudget}`
    );
  });
} catch (err) {
  console.error('ERROR:', err);
} finally {
  // Close the database when finished.
  database.close();
}

PHP

use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Database;

/**
 * Queries sample data using SQL with query options.
 * Example:
 * ```
 * query_data_with_query_options($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function query_data_with_query_options($instanceId, $databaseId)
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $results = $database->execute(
        'SELECT VenueId, VenueName, LastUpdateTime FROM Venues',
        [
            'queryOptions' => [
                'optimizerVersion' => "1"
            ]
        ]
    );

    foreach ($results as $row) {
        printf('VenueId: %s, VenueName: %s, LastUpdateTime: %s' . PHP_EOL,
            $row['VenueId'], $row['VenueName'], $row['LastUpdateTime']);
    }
}

Python

# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)

with database.snapshot() as snapshot:
    results = snapshot.execute_sql(
        "SELECT VenueId, VenueName, LastUpdateTime FROM Venues",
        query_options={"optimizer_version": "1"},
    )

    for row in results:
        print(u"VenueId: {}, VenueName: {}, LastUpdateTime: {}".format(*row))

Ruby

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new project: project_id
client  = spanner.client instance_id, database_id

sql_query = "SELECT VenueId, VenueName, LastUpdateTime FROM Venues"
query_options = { optimizer_version: "1" }

client.execute(sql_query, query_options: query_options).rows.each do |row|
  puts "#{row[:VenueId]} #{row[:VenueName]} #{row[:LastUpdateTime]}"
end

문 힌트를 사용하여 쿼리의 최적화 도구 버전 설정

문 힌트는 쿼리 실행을 기본 동작에서 변경하는 쿼리 문의 힌트입니다. 문에서 OPTIMIZER_VERSION 힌트를 설정하면 지정된 쿼리 최적화 도구 버전을 사용하여 해당 쿼리가 실행됩니다.

OPTIMIZER_VERSION 힌트의 최적화 도구 버전 우선순위가 가장 높습니다. 문 힌트가 지정되면 다른 모든 최적화 도구 버전 설정과 상관없이 사용됩니다.

@{OPTIMIZER_VERSION=2} SELECT * FROM MyTable

또한 다음과 같이 latest 리터럴을 사용하여 쿼리의 최적화 도구 버전을 최신 버전으로 설정할 수도 있습니다.

@{OPTIMIZER_VERSION=latest} SELECT * FROM MyTable

JDBC 드라이버 사용 시 최적화 도구 버전 설정

다음 예시와 같이 JDBC 연결 문자열에 버전을 지정하여 최적화 도구 버전의 기본값을 재정의할 수 있습니다.

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

class ConnectionWithQueryOptionsExample {

  static void connectionWithQueryOptions() throws SQLException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    connectionWithQueryOptions(projectId, instanceId, databaseId);
  }

  @SuppressFBWarnings(
      value = "OBL_UNSATISFIED_OBLIGATION",
      justification = "https://github.com/spotbugs/spotbugs/issues/293")
  static void connectionWithQueryOptions(String projectId, String instanceId, String databaseId)
      throws SQLException {
    String optimizerVersion = "1";
    String connectionUrl =
        String.format(
            "jdbc:cloudspanner:/projects/%s/instances/%s/databases/%s?optimizerVersion=%s",
            projectId, instanceId, databaseId, optimizerVersion);
    try (Connection connection = DriverManager.getConnection(connectionUrl);
        Statement statement = connection.createStatement()) {
      // Execute a query using the optimizer version '1'.
      try (ResultSet rs =
          statement.executeQuery(
              "SELECT SingerId, FirstName, LastName FROM Singers ORDER BY LastName")) {
        while (rs.next()) {
          System.out.printf("%d %s %s%n", rs.getLong(1), rs.getString(2), rs.getString(3));
        }
      }
      try (ResultSet rs = statement.executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
        while (rs.next()) {
          System.out.printf("Optimizer version: %s%n", rs.getString(1));
        }
      }
    }
  }
}

다음 예시와 같이 SET OPTIMIZER_VERSION 문을 사용하여 쿼리 최적화 도구 버전을 설정할 수도 있습니다.

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

class SetQueryOptionsExample {

  static void setQueryOptions() throws SQLException {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    setQueryOptions(projectId, instanceId, databaseId);
  }

  @SuppressFBWarnings(
      value = "OBL_UNSATISFIED_OBLIGATION",
      justification = "https://github.com/spotbugs/spotbugs/issues/293")
  static void setQueryOptions(String projectId, String instanceId, String databaseId)
      throws SQLException {
    String connectionUrl =
        String.format(
            "jdbc:cloudspanner:/projects/%s/instances/%s/databases/%s",
            projectId, instanceId, databaseId);
    try (Connection connection = DriverManager.getConnection(connectionUrl);
        Statement statement = connection.createStatement()) {
      // Instruct the JDBC connection to use version '1' of the query optimizer.
      statement.execute("SET OPTIMIZER_VERSION='1'");
      // Execute a query using the latest optimizer version.
      try (ResultSet rs =
          statement.executeQuery(
              "SELECT SingerId, FirstName, LastName FROM Singers ORDER BY LastName")) {
        while (rs.next()) {
          System.out.printf("%d %s %s%n", rs.getLong(1), rs.getString(2), rs.getString(3));
        }
      }
      try (ResultSet rs = statement.executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
        while (rs.next()) {
          System.out.printf("Optimizer version: %s%n", rs.getString(1));
        }
      }
    }
  }
}

오픈소스 드라이버 사용에 대한 자세한 내용은 오픈소스 JDBC 드라이버 사용을 참조하세요.

잘못된 최적화 도구 버전 처리 방법

Cloud Spanner는 넓은 범위의 최적화 도구 버전을 지원합니다. 이러한 범위는 시간 경과에 따라 쿼리 최적화 도구가 업데이트되면 변경됩니다. 이 가이드에 설명된 방법 중 하나를 사용할 때 지정한 버전이 범위를 벗어나면 Cloud Spanner가 쿼리에 실패합니다. 예를 들어 최적화 도구 버전 = 100으로 쿼리를 실행하려고 하는데 해당 값이 현재 최댓값을 초과한다면 다음과 같은 오류가 발생합니다.

Query optimizer version: 100 is not supported

쿼리를 실행하는 데 사용되는 쿼리 최적화 도구 버전 확인

쿼리에 사용된 최적화 도구 버전은 gcloud spanner와 Cloud Console에 표시됩니다.

gcloud spanner

gcloud spanner에서 쿼리를 실행할 때 사용되는 버전을 확인하려면 아래 스니펫과 같이 --query-mode 플래그를 PROFILE로 설정합니다.

gcloud spanner databases execute-sql MyDatabase --instance=test-instance \
    --query-mode=PROFILE --sql='SELECT * FROM MyTable'

Cloud Console

쿼리에 사용된 최적화 도구 버전을 보려면 Cloud Console의 쿼리 데이터베이스 보기에서 쿼리를 실행한 다음 설명 탭을 선택합니다. 다음과 유사한 메시지가 표시됩니다.

최적화 도구 버전 2를 사용하여 쿼리가 실행되었습니다.

측정항목 탐색기에서 쿼리 최적화 도구 버전 시각화

Cloud Monitoring은 애플리케이션과 시스템 서비스의 성능을 파악하는 데 도움이 되는 측정 값을 수집합니다. Cloud Spanner를 위해 수집되는 측정항목 중 하나는 일정 기간에 따라 샘플링된 한 인스턴스의 쿼리 수를 측정하는 쿼리 수입니다. 이 측정항목은 오류 코드로 그룹화된 쿼리를 볼 때 매우 유용하지만, 각 쿼리 실행에 사용된 옵티마이저 버전을 확인하는 데에도 사용할 수 있습니다.

Cloud Console의 측정항목 탐색기를 사용하여 데이터베이스 인스턴스의 쿼리 수를 시각화할 수 있습니다. 그림 1은 3개 데이터베이스의 쿼리 수를 보여줍니다. 각 데이터베이스에서 사용 중인 옵티마이저 버전을 확인할 수 있습니다.

이 그림의 차트 아래에 있는 표는 my-db-1이 잘못된 최적화 도구 버전으로 쿼리를 실행하려 시도하여 잘못된 사용 상태가 반환되고 쿼리 수가 0이 되었음을 보여줍니다. 다른 데이터베이스는 각각 최적화 도구 버전 1 및 2를 사용하여 쿼리를 실행했습니다.

쿼리 최적화 버전으로 그룹화된 측정항목 탐색기 내의 쿼리 수

그림 1. 최적화 그룹 버전별로 그룹화된 쿼리로 측정항목 탐색기에 표시되는 쿼리 수

인스턴스에 대해 비슷한 차트를 설정하려면 다음 안내를 따르세요.

  1. Cloud Console에서 측정항목 탐색기로 이동합니다.
  2. 리소스 유형 필드에서 Cloud Spanner Instance를 선택합니다.
  3. 측정항목 필드에서 Count of queries를 선택합니다.
  4. 그룹화 기준 필드에서 database, optimizer_version, status를 선택합니다.

이 예에서는 동일한 데이터베이스의 여러 쿼리에 다른 최적화 도구 버전을 사용하는 경우에 대해서는 설명하지 않습니다. 이 경우 차트에는 데이터베이스 및 최적화 도구 버전의 각 조합에 대한 막대 세그먼트가 표시됩니다.

Cloud Monitoring을 사용하여 Cloud Spanner 인스턴스를 모니터링하는 방법은 Cloud Monitoring으로 모니터링을 참조하세요.