Abfrageoptimierung verwalten

Auf dieser Seite wird beschrieben, wie Sie den Abfrageoptimierer in Spanner für Datenbanken mit GoogleSQL- und PostgreSQL-Dialekt verwalten.

Der Spanner-Abfrageoptimierer ermittelt die effizienteste Ausführungsmethode für eine SQL-Abfrage. Der vom Optimierer ermittelte Abfrageplan kann sich jedoch geringfügig ändern, wenn sich das Abfrageoptimierungstool weiterentwickelt oder die Datenbankstatistiken aktualisiert werden. Um das Risiko einer Leistungsregression zu minimieren, wenn sich das Abfrageoptimierungstool oder die Statistiken ändern, bietet Spanner die folgenden Abfrageoptionen.

  • optimizer_version: Änderungen am Abfrageoptimierer werden gebündelt und als Abfrageoptimierungsversionen veröffentlicht. Spanner verwendet die neueste Version des Optimierungstools mindestens 30 Tage nach der Veröffentlichung als Standard. Mit der Option „Version des Abfrageoptimierungstools“ können Sie Abfragen für eine ältere Version des Optimierungstools ausführen.

  • optimizer_statistics_package: Spanner aktualisiert Optimierungsstatistiken regelmäßig. Neue Statistiken werden als Paket verfügbar gemacht. Mit dieser Abfrageoption wird ein Statistikpaket für das Abfrageoptimierungstool angegeben, das beim Kompilieren einer SQL-Abfrage verwendet werden soll. Für das angegebene Paket muss die automatische Speicherbereinigung deaktiviert sein:

 ALTER STATISTICS <package_name> SET OPTIONS (allow_gc=false)
ALTER STATISTICS spanner."<package_name>" SET OPTIONS (allow_gc = true)

In diesem Leitfaden wird gezeigt, wie Sie diese einzelnen Optionen in Spanner auf verschiedenen Ebenen festlegen.

Optionen für die Abfrageoptimierung auflisten

In Spanner werden Informationen zu den verfügbaren Optimierungsversionen und Statistikpaketen gespeichert, die Sie auswählen können.

Versionen des Optimierungstools

Die Version des Abfrageoptimierungstools ist ein ganzzahliger Wert, der bei jeder Aktualisierung um 1 erhöht wird. Die neueste Version des Abfrageoptimierungstools ist 8.

Führen Sie die folgende SQL-Anweisung aus, damit eine Liste aller unterstützten Versionen des Optimierungstools zusammen mit den entsprechenden Releasedaten und der Information zurückgegeben wird, ob diese Version die Standardversion ist. Die größte zurückgegebene Versionsnummer ist die neueste unterstützte Version des Optimierungstools.

SELECT * FROM SPANNER_SYS.SUPPORTED_OPTIMIZER_VERSIONS;

Standardversion

Standardmäßig verwendet Spanner die neueste Version des Optimierungstools frühestens 30 Tage nach der Veröffentlichung dieser Version. Während dieses Zeitraums von mehr als 30 Tagen zwischen dem neuen Release und der Übernahme dieses Releases als Standard sollten Sie Abfragen mit der neuen Version testen, um eventuelle Regressionen zu erkennen.

Führen Sie die folgende SQL-Anweisung aus, um die Standardversion zu ermitteln:

SELECT * FROM SPANNER_SYS.SUPPORTED_OPTIMIZER_VERSIONS;

Die Abfrage gibt eine Liste aller unterstützten Optimierungsversionen zurück. In der Spalte IS_DEFAULT wird angegeben, welche Version die aktuelle Standardversion ist.

Weitere Informationen zu den einzelnen Versionen finden Sie unter Versionsverlauf des Abfrageoptimierungstools.

Statistikpakete für das Abfrageoptimierungstool

Jedem neuen Statistikpaket des Abfrageoptimierungstools, das von Spanner erstellt wird, wird ein Paketname zugewiesen, der innerhalb der jeweiligen Datenbank garantiert eindeutig ist.

Das Format des Paketnamens ist auto_{PACKAGE_TIMESTAMP}UTC. In GoogleSQL wird mit der Anweisung ANALYZE der Name des Statistikpakets erstellt. In PostgreSQL wird diese Aufgabe durch die Anweisung ANALYZE ausgeführt. Der Name des Statistikpakets hat das Format analyze_{PACKAGE_TIMESTAMP}UTC, wobei {PACKAGE_TIMESTAMP} der Zeitstempel in der UTC-Zeitzone ist, zu dem die Erstellung der Statistiken gestartet wurde. Führen Sie die folgende SQL-Anweisung aus, um eine Liste aller verfügbaren Statistikpakete für den Optimierer zurückzugeben.

SELECT * FROM INFORMATION_SCHEMA.SPANNER_STATISTICS;

Standardmäßig verwendet Spanner das neueste Statistikpaket für das Abfrageoptimierungstool, es sei denn, die Datenbank oder Abfrage ist mithilfe einer der auf dieser Seite beschriebenen Methoden an ein älteres Paket angepinnt.

Rangordnung der Optionenüberschreibung

Wenn Sie eine Datenbank mit GoogleSQL-Dialekt verwenden, bietet Spanner mehrere Möglichkeiten, die Optimierungsoptionen zu ändern. Sie können beispielsweise die Optionen für eine bestimmte Abfrage festlegen oder die Optionen in der Clientbibliothek auf Prozess- oder Abfrageebene konfigurieren. Wenn eine Option auf mehrere Arten festgelegt wird, gilt die folgende Rangordnung. Wählen Sie einen Link aus, um zu diesem Abschnitt in diesem Dokument zu springen.

Spanner-Standardeinstellung ← DatenbankoptionClient-AnwendungUmgebungsvariableClientabfrageAnweisungshinweis

So können Sie beispielsweise die Reihenfolge der Prioritäten beim Festlegen der Version des Abfrageoptimators interpretieren:

Beim Erstellen einer Datenbank wird die Standardversion des Optimierungstools von Spanner verwendet. Das Festlegen der Version des Optimierungstools mit einer der oben aufgeführten Methoden hat Vorrang vor allen links daneben stehenden Methoden. Beispielsweise hat das Festlegen des Optimierungstools für eine Anwendung mithilfe einer Umgebungsvariable Vorrang vor allen Werten, die Sie mit der Datenbankoption für die Datenbank festlegen. Das Festlegen der Version des Optimierungstools über einen Anweisungshinweis hat die höchste Priorität für die angegebene Abfrage, wobei der mit einer anderen Methode festgelegte Wert Vorrang hat.

In den folgenden Abschnitten finden Sie weitere Informationen zu den einzelnen Methoden.

Optimierungsoptionen auf Datenbankebene festlegen

Mit dem folgenden DDL-Befehl vom Typ ALTER DATABASE können Sie die Standardversion des Optimierungstools für eine Datenbank festlegen.

ALTER DATABASE MyDatabase
SET OPTIONS (optimizer_version =  8);
ALTER DATABASE MyDatabase SET spanner.optimizer_version = 5;

Sie können das Statistikpaket ähnlich festlegen, wie im folgenden Beispiel gezeigt.

ALTER DATABASE MyDatabase
SET OPTIONS (optimizer_statistics_package = "auto_20191128_14_47_22UTC");
ALTER DATABASE MyDatabase
SET spanner.optimizer_statistics_package = "auto_20191128_14_47_22UTC";

Sie können auch mehrere Optionen gleichzeitig festlegen, wie im folgenden DDL-Befehl gezeigt.

ALTER DATABASE MyDatabase
SET OPTIONS (optimizer_version = 8,
            optimizer_statistics_package = "auto_20191128_14_47_22UTC");

Sie können ALTER DATABASE in der gcloud CLI mit dem Befehl gcloud CLI databases ddl update folgendermaßen ausführen.

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

Wenn Sie eine Datenbankoption auf NULL (in GoogleSQL) oder DEFAULT (in PostgreSQL) festlegen, wird sie gelöscht und der Standardwert wird verwendet.

Wenn Sie den aktuellen Wert dieser Optionen für eine Datenbank sehen möchten, stellen Sie eine Abfrage für die Ansicht INFORMATION_SCHEMA.DATABASE_OPTIONS für GoogleSQL oder die Tabelle information_schema database_options für PostgreSQL.

SELECT
  s.OPTION_NAME,
  s.OPTION_VALUE
FROM
  INFORMATION_SCHEMA.DATABASE_OPTIONS s
WHERE
  s.SCHEMA_NAME=""
  AND s.OPTION_NAME IN ('optimizer_version', 'optimizer_statistics_package')
  SELECT
    s.option_name,
    s.option_value
  FROM
    information_schema.database_options s
  WHERE
    s.schema_name='public'
    AND s.option_name IN ('optimizer_version',
      'optimizer_statistics_package')

Optimierungsoptionen mit Clientbibliotheken festlegen

Wenn Sie programmgesteuert über Clientbibliotheken mit Spanner interagieren, gibt es mehrere Möglichkeiten, die Abfrageoptionen für Ihre Clientanwendung zu ändern.

Sie müssen die neuesten Versionen der Clientbibliotheken verwenden, um Optimiereroptionen festzulegen.

Optimierungsoptionen für einen Datenbankclient festlegen

Eine Anwendung kann Optimierungsoptionen global für die Clientbibliothek festlegen. Dazu wird die Eigenschaft der Abfrageoptionen wie in den folgenden Code-Snippets konfiguriert. Die Optimierungseinstellungen werden in der Clientinstanz gespeichert und auf alle Abfragen angewendet, die während der Lebensdauer des Clients ausgeführt werden. Auch wenn die Optionen auf Datenbankebene im Back-End gelten, gelten die Optionen auf Client-Ebene für alle Datenbanken, die über diesen Client verbunden sind.

namespace spanner = ::google::cloud::spanner;
spanner::Client client(
    spanner::MakeConnection(db),
    google::cloud::Options{}
        .set<spanner::QueryOptimizerVersionOption>("1")
        .set<spanner::QueryOptimizerStatisticsPackageOption>(
            "auto_20191128_14_47_22UTC"));

using Google.Cloud.Spanner.Data;
using System.Collections.Generic;
using System.Threading.Tasks;

public class CreateConnectionWithQueryOptionsAsyncSample
{
    public class Album
    {
        public int AlbumId { get; set; }
        public int SingerId { get; set; }
        public string AlbumTitle { get; set; }
    }

    public async Task<List<Album>> CreateConnectionWithQueryOptionsAsync(string projectId, string instanceId, string databaseId)
    {
        string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";

        using var connection = new SpannerConnection(connectionString)
        {
            // Set query options on the connection.
            QueryOptions = QueryOptions.Empty
                .WithOptimizerVersion("1")
                // The list of available statistics packages for the database can
                // be found by querying the "INFORMATION_SCHEMA.SPANNER_STATISTICS"
                // table.
                .WithOptimizerStatisticsPackage("latest")
        };

        var albums = new List<Album>();
        var cmd = connection.CreateSelectCommand("SELECT SingerId, AlbumId, AlbumTitle FROM Albums");
        using var reader = await cmd.ExecuteReaderAsync();
        while (await reader.ReadAsync())
        {
            albums.Add(new Album
            {
                SingerId = reader.GetFieldValue<int>("SingerId"),
                AlbumId = reader.GetFieldValue<int>("AlbumId"),
                AlbumTitle = reader.GetFieldValue<string>("AlbumTitle")
            });
        }
        return albums;
    }
}

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

	"cloud.google.com/go/spanner"
	sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
	"google.golang.org/api/iterator"
)

func createClientWithQueryOptions(w io.Writer, database string) error {
	ctx := context.Background()
	queryOptions := spanner.QueryOptions{
		Options: &sppb.ExecuteSqlRequest_QueryOptions{
			OptimizerVersion: "1",
			// The list of available statistics packages can be found by
			// querying the "INFORMATION_SCHEMA.SPANNER_STATISTICS" table.
			OptimizerStatisticsPackage: "latest",
		},
	}
	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")
                  // The list of available statistics packages can be found by querying the
                  // "INFORMATION_SCHEMA.SPANNER_STATISTICS" table.
                  .setOptimizerStatisticsPackage("latest")
                  .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));
    }
  }
}
// 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',
    // The list of available statistics packages can be found by querying the
    // "INFORMATION_SCHEMA.SPANNER_STATISTICS" table.
    optimizerStatisticsPackage: 'latest',
  }
);

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();
}
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(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient([
        'queryOptions' => [
            'optimizerVersion' => '1',
            // Pin the statistics package used for this client instance to the
            // latest version. The list of available statistics packages can be
            // found by querying the "INFORMATION_SCHEMA.SPANNER_STATISTICS"
            // table.
            'optimizerStatisticsPackage' => 'latest'
        ]
    ]);
    $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']);
    }
}
# instance_id = "your-spanner-instance"
# database_id = "your-spanner-db-id"
spanner_client = spanner.Client(
    query_options={
        "optimizer_version": "1",
        "optimizer_statistics_package": "latest",
    }
)
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("VenueId: {}, VenueName: {}, LastUpdateTime: {}".format(*row))
# 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",
  # The list of available statistics packages can be
  # found by querying the "INFORMATION_SCHEMA.SPANNER_STATISTICS"
  # table.
  optimizer_statistics_package: "latest"
}

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

Optimierungsoptionen mit Umgebungsvariablen festlegen

Damit Sie verschiedene Optimierungseinstellungen einfacher ausprobieren können, ohne die Anwendung neu kompilieren zu müssen, können Sie die Umgebungsvariablen SPANNER_OPTIMIZER_VERSION und SPANNER_OPTIMIZER_STATISTICS_PACKAGE festlegen und die Anwendung ausführen, wie im folgenden Snippet gezeigt.

export SPANNER_OPTIMIZER_VERSION="8"
export SPANNER_OPTIMIZER_STATISTICS_PACKAGE="auto_20191128_14_47_22UTC"
set SPANNER_OPTIMIZER_VERSION="8"
  set SPANNER_OPTIMIZER_STATISTICS_PACKAGE="auto_20191128_14_47_22UTC"

Die angegebenen Werte für die Abfrageoptimierungsoptionen werden zum Zeitpunkt der Client-Initialisierung in der Client-Instanz gelesen und gespeichert und auf alle Abfragen angewendet, die während der Lebensdauer des Clients ausgeführt werden.

Optimierungsoptionen für eine Clientabfrage festlegen

Sie können einen Wert für die Optimierungsversion oder die Version des Statistikpakets auf Abfrageebene in Ihrer Client-Anwendung angeben, wenn Sie beim Erstellen der Abfrage eine Eigenschaft für die Abfrageoptionen angeben.

void QueryWithQueryOptions(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;
  auto sql = spanner::SqlStatement("SELECT SingerId, FirstName FROM Singers");
  auto opts =
      google::cloud::Options{}
          .set<spanner::QueryOptimizerVersionOption>("1")
          .set<spanner::QueryOptimizerStatisticsPackageOption>("latest");
  auto rows = client.ExecuteQuery(std::move(sql), std::move(opts));

  using RowType = std::tuple<std::int64_t, std::string>;
  for (auto& row : spanner::StreamOf<RowType>(rows)) {
    if (!row) throw std::move(row).status();
    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";
}

using Google.Cloud.Spanner.Data;
using System.Collections.Generic;
using System.Threading.Tasks;

public class RunCommandWithQueryOptionsAsyncSample
{
    public class Album
    {
        public int SingerId { get; set; }
        public int AlbumId { get; set; }
        public string AlbumTitle { get; set; }
    }

    public async Task<List<Album>> RunCommandWithQueryOptionsAsync(string projectId, string instanceId, string databaseId)
    {
        var connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";
        using var connection = new SpannerConnection(connectionString);
        using var cmd = connection.CreateSelectCommand("SELECT SingerId, AlbumId, AlbumTitle FROM Albums");

        cmd.QueryOptions = QueryOptions.Empty
            .WithOptimizerVersion("1")
            // The list of available statistics packages for the database can
            // be found by querying the "INFORMATION_SCHEMA.SPANNER_STATISTICS"
            // table.
            .WithOptimizerStatisticsPackage("latest");
        var albums = new List<Album>();
        using var reader = await cmd.ExecuteReaderAsync();
        while (await reader.ReadAsync())
        {
            albums.Add(new Album()
            {
                AlbumId = reader.GetFieldValue<int>("AlbumId"),
                SingerId = reader.GetFieldValue<int>("SingerId"),
                AlbumTitle = reader.GetFieldValue<string>("AlbumTitle")
            });
        }
        return albums;
    }
}

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

	"cloud.google.com/go/spanner"
	sppb "cloud.google.com/go/spanner/apiv1/spannerpb"
	"google.golang.org/api/iterator"
)

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",
			// The list of available statistics packages can be found by
			// querying the "INFORMATION_SCHEMA.SPANNER_STATISTICS" table.
			OptimizerStatisticsPackage: "latest",
		},
	}
	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")
                      // The list of available statistics packages can be found by querying the
                      // "INFORMATION_SCHEMA.SPANNER_STATISTICS" table.
                      .setOptimizerStatisticsPackage("latest")
                      .build())
                  .build())) {
    while (resultSet.next()) {
      System.out.printf(
          "%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1), resultSet.getString(2));
    }
  }
}
// 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',
    // The list of available statistics packages can be found by querying the
    // "INFORMATION_SCHEMA.SPANNER_STATISTICS" table.
    optimizerStatisticsPackage: '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();
}
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(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $results = $database->execute(
        'SELECT VenueId, VenueName, LastUpdateTime FROM Venues',
        [
            'queryOptions' => [
                'optimizerVersion' => '1',
                // Pin the statistics package to the latest version just for
                // this query.
                'optimizerStatisticsPackage' => 'latest'
            ]
        ]
    );

    foreach ($results as $row) {
        printf('VenueId: %s, VenueName: %s, LastUpdateTime: %s' . PHP_EOL,
            $row['VenueId'], $row['VenueName'], $row['LastUpdateTime']);
    }
}
# 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",
            "optimizer_statistics_package": "latest",
        },
    )

    for row in results:
        print("VenueId: {}, VenueName: {}, LastUpdateTime: {}".format(*row))
# 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",
  # The list of available statistics packagebs can be
  # found by querying the "INFORMATION_SCHEMA.SPANNER_STATISTICS"
  # table.
  optimizer_statistics_package: "latest"
}

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

Optimierungsoptionen für eine Abfrage mithilfe eines Anweisungshinweises festlegen

Ein Anweisungshinweis ist ein Hinweis auf eine Abfrageanweisung, durch den die Ausführung der Abfrage vom Standardverhalten abweicht. Wenn Sie den OPTIMIZER_VERSION-Hinweis für eine Anweisung festlegen, wird die Ausführung der Abfrage mit der angegebenen Version des Abfrageoptimierungstools erzwungen.

Der OPTIMIZER_VERSION-Hinweis hat die höchste Priorität in Bezug auf die Version des Optimierungstools. Wenn der Hinweis zur Anweisung angegeben ist, wird er unabhängig von allen anderen Einstellungen der Optimierungstoolversion verwendet.

@{OPTIMIZER_VERSION=8} SELECT * FROM MyTable;
/*@OPTIMIZER_VERSION=8*/ SELECT * FROM MyTable;

Sie können auch das Literal latest_version verwenden, um die Optimierungsversion für eine Abfrage wie hier gezeigt auf die neueste Version festzulegen.

@{OPTIMIZER_VERSION=latest_version} SELECT * FROM MyTable;
/*@OPTIMIZER_VERSION=latest_version*/ SELECT * FROM MyTable;

Wenn Sie den OPTIMIZER_STATISTICS_PACKAGE-Hinweis für eine Anweisung festlegen, wird die Ausführung der Abfrage mit der angegebenen Version des Statistikpakets für das Abfrageoptimierungstool erzwungen. Für das angegebene Paket muss die automatische Speicherbereinigung deaktiviert sein:

ALTER STATISTICS <package_name> SET OPTIONS (allow_gc=false)
ALTER STATISTICS spanner."package_name" SET OPTIONS (allow_gc=false)

Der OPTIMIZER_STATISTICS_PACKAGE-Hinweis hat die höchste Priorität in Bezug auf die Einstellungen des Optimierungspakets. Wenn der Hinweis zur Anweisung angegeben ist, wird er unabhängig von allen anderen Einstellungen der Optimierungstoolversion verwendet.

@{OPTIMIZER_STATISTICS_PACKAGE=auto_20191128_14_47_22UTC} SELECT * FROM MyTable;

Sie können auch das Literal latest verwenden, um das neueste Statistikpaket zu verwenden.

@{OPTIMIZER_STATISTICS_PACKAGE=latest} SELECT * FROM MyTable;

Beide Hinweise können in einer einzigen Anweisung festgelegt werden, wie im folgenden Beispiel gezeigt.

Mit dem Literal default_version wird die Optimierungsversion für eine Abfrage auf die Standardversion festgelegt, die sich von der neuesten Version unterscheiden kann. Weitere Informationen finden Sie unter Standardversion.

@{OPTIMIZER_VERSION=default_version, OPTIMIZER_STATISTICS_PACKAGE=auto_20191128_14_47_22UTC} SELECT * FROM MyTable;
/*@OPTIMIZER_VERSION=default_version, OPTIMIZER_STATISTICS_PACKAGE=auto_20191128_14_47_22UTC*/ SELECT * FROM KeyValue;

Optimierungsoptionen bei Verwendung des Spanner-JDBC-Treibers festlegen

Sie können den Standardwert der Optimierungstoolversion und des Statistikpakets überschreiben, indem Sie wie im folgenden Beispiel gezeigt Optionen im JDBC-Verbindungsstring angeben.

Diese Optionen werden nur in den neuesten Versionen des Spanner JDBC-Treibers unterstützt.

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);
  }

  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));
        }
      }
    }
  }
}

Sie können die Version des Abfrageoptimierungstools auch wie im folgenden Beispiel gezeigt mit der Anweisung SET OPTIMIZER_VERSION festlegen.

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);
  }

  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.
      // NOTE: Use `SET SPANNER.OPTIMIZER_VERSION='1`` when connected to a PostgreSQL database.
      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));
        }
      }
      // NOTE: Use `SHOW SPANNER.OPTIMIZER_VERSION` when connected to a PostgreSQL database.
      try (ResultSet rs = statement.executeQuery("SHOW VARIABLE OPTIMIZER_VERSION")) {
        while (rs.next()) {
          System.out.printf("Optimizer version: %s%n", rs.getString(1));
        }
      }
    }
  }
}

Weitere Informationen zur Verwendung des Open-Source-Treibers finden Sie unter Open-Source-JDBC-Treiber verwenden.

Umgang mit ungültigen Optimierungstoolversionen

Spanner unterstützt mehrere Versionen des Optimierungstools. Welche Versionen unterstützt werden, ändert sich von Zeit zu Zeit, wenn das Abfrageoptimierungstool aktualisiert wird. Wenn die angegebene Version außerhalb des zulässigen Bereichs liegt, schlägt die Abfrage fehl. Wenn Sie beispielsweise versuchen, eine Abfrage mit dem Anweisungshinweis @{OPTIMIZER_VERSION=9} auszuführen, die aktuelle Optimierungstoolversion aber nur 8 ist, gibt Spanner die folgende Fehlermeldung zurück:

Query optimizer version: 9 is not supported

Umgang mit einer ungültigen Einstellung für das Statistikpaket des Abfrageoptimierungstools

Sie können Ihre Datenbank oder Abfrage mit einer der oben beschriebenen Methoden an ein beliebiges verfügbares Statistikpaket anpinnen. Eine Abfrage schlägt fehl, wenn ein ungültiger Statistikpaketname angegeben wird. Ein Statistikpaket, das in einer Abfrage angegeben wird, muss entweder

Version des Optimierungstools für Abfragen festlegen, die zum Ausführen einer Abfrage verwendet wird

Die für eine Abfrage verwendete Version des Optimierungstools ist in der Google Cloud Console und in der Google Cloud CLI sichtbar.

Führen Sie die Abfrage auf der Seite Spanner Studio der Google Cloud Console aus und wählen Sie dann den Tab Erklärung aus, um die für eine Abfrage verwendete Version des Optimierungstools aufzurufen. Es wird eine Meldung ähnlich der folgenden angezeigt:

Version der Abfrageoptimierung: 8

Wenn Sie die Version aufrufen möchten, die beim Ausführen einer Abfrage in der gcloud CLI verwendet wird, setzen Sie das Flag --query-mode wie im folgenden Snippet gezeigt auf PROFILE.

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

Version der Abfrageoptimierung im Metrics Explorer visualisieren

Cloud Monitoring erfasst Messwerte, um die Leistung Ihrer Anwendungen und Systemdienste besser zu verstehen. Einer der für Spanner erfassten Messwerte ist die Anzahl der Abfragen. Damit wird die Anzahl der Abfragen in einer Instanz gemessen, die im Laufe der Zeit erfasst wurden. Dieser Messwert ist zwar sehr hilfreich, um Abfragen aufzurufen, die nach Fehlercode gruppiert sind, wir können ihn aber auch verwenden, um zu sehen, welche Version des Optimierungstools zur Ausführung der einzelnen Abfragen verwendet wurde.

Mit dem Metrics Explorer in der Google Cloud Console können Sie die Anzahl der Abfragen für Ihre Datenbankinstanz visualisieren. Abbildung 1 zeigt die Anzahl der Abfragen für drei Datenbanken. Sie sehen, welche Version des Optimierungstools in den einzelnen Datenbanken verwendet wird.

Die Tabelle unter dem Diagramm in dieser Abbildung zeigt, dass my-db-1 versucht hat, eine Abfrage mit einer ungültigen Optimierungstoolversion auszuführen, was den Status Falsche Nutzung zurückgibt und zu einer Abfrageanzahl von 0 führt. Die anderen Datenbanken haben Abfragen mit den Versionen 1 und 2 des Optimierungstools ausgeführt.

Grafik: Anzahl der Abfragen im Metrics Explorer nach der Version der Abfrageoptimierung

Abbildung 1. Anzahl der Abfragen, die im Metrics Explorer zusammen mit Abfragen angezeigt werden, die nach der Optimierungsversion gruppiert sind.

So richten Sie ein ähnliches Diagramm für Ihre Instanz ein:

  1. Rufen Sie in der Google Cloud Console den Metrics Explorer auf.
  2. Wählen Sie im Feld Ressourcentyp Cloud Spanner Instance aus.
  3. Wählen Sie im Feld Messwert die Option Count of queries aus.
  4. Wählen Sie im Feld Gruppieren nach die Optionen database, optimizer_version und status aus.

In diesem Beispiel wird nicht der Fall gezeigt, bei dem für verschiedene Abfragen in derselben Datenbank eine andere Optimierungstoolversion verwendet wird. In diesem Fall würde das Diagramm ein Balkendiagramm für jede Kombination aus Datenbank- und Optimierungstoolversion zeigen.

Informationen zum Monitoring Ihrer Spanner-Instanzen mit Cloud Monitoring finden Sie unter Monitoring mit Cloud Monitoring.