Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Erste Schritte mit Cloud Spanner in C++

Ziele

In dieser Anleitung werden Sie durch die folgenden Schritte mit der Cloud Spanner-Clientbibliothek für C++ geführt:

  • Cloud Spanner-Instanz und -Datenbank erstellen
  • SQL-Abfragen für Daten in der Datenbank schreiben, lesen und ausführen
  • Datenbankschema aktualisieren
  • Daten mit einer Lese-Schreib-Transaktion aktualisieren
  • Sekundären Index für die Datenbank hinzufügen
  • Mit dem Index Daten lesen und SQL-Abfragen ausführen
  • Daten über eine schreibgeschützte Transaktion abrufen

Kosten

In dieser Anleitung wird Cloud Spanner verwendet, eine kostenpflichtige Komponente von Google Cloud. Informationen zu den Kosten der Nutzung von Cloud Spanner finden Sie unter Preise.

Hinweis

Führen Sie die unter Einrichten beschriebenen Schritte aus, die das Erstellen und Festlegen eines standardmäßigen Google Cloud-Projekts, das Aktivieren der Rechnungsstellung, das Aktivieren der Cloud Spanner API und das Einrichten von OAuth 2.0 umfassen, um Anmeldedaten für die Authentifizierung für die Verwendung der Cloud Spanner API zu erhalten.

Sie müssen insbesondere gcloud auth application-default login ausführen, um die lokale Entwicklungsumgebung mit Anmeldedaten für die Authentifizierung einzurichten.

Lokale C++-Umgebung vorbereiten

  1. Klonen Sie das Repository der Beispiel-App auf Ihren lokalen Computer:

    git clone https://github.com/googleapis/google-cloud-cpp $HOME/google-cloud-cpp
    
  2. Installieren Sie Bazel für Linux mithilfe dieser Anleitung.

  3. Wechseln Sie in das Verzeichnis, das den Cloud Spanner-Beispielcode enthält:

    cd $HOME/google-cloud-cpp
    
  4. Erstellen Sie die Beispiele mit diesem Befehl:

    bazel build //google/cloud/spanner/samples:samples
    
  5. Richten Sie die Authentifizierung und Autorisierung für das Projekt google-cloud-cpp ein.

    gcloud auth application-default login
    
  6. Erstellen Sie eine Umgebungsvariable mit dem Namen GCLOUD_PROJECT. Ersetzen Sie [MY_PROJECT_ID] durch die Google Cloud-Projekt-ID. Sie finden sie im Dashboard Ihres Projekts.

    export GCLOUD_PROJECT=[MY_PROJECT_ID]
    

Instanz erstellen

Wenn Sie Cloud Spanner zum ersten Mal verwenden, müssen Sie eine Instanz erstellen. Dabei handelt es sich um eine Zuordnung von Ressourcen, die von Cloud Spanner-Datenbanken verwendet werden. Wenn Sie eine Instanz erstellen, müssen Sie eine Instanzkonfiguration auswählen. Abhängig davon werden der Speicherort Ihrer Daten sowie die Anzahl der zu verwendenden Knoten festgelegt. Anhand der Knotenanzahl wird dann die Menge der Bereitstellungs- und Speicherressourcen in Ihrer Instanz festgelegt.

Führen Sie den folgenden Befehl aus, um eine Cloud Spanner-Instanz in der Region us-central1 mit nur einem Knoten zu erstellen:

gcloud spanner instances create test-instance --config=regional-us-central1 \
    --description="Test Instance" --nodes=1

Dadurch wird eine Instanz mit diesen Properties erstellt:

  • Instanz-ID test-instance
  • Anzeigename Test Instance
  • Instanzkonfiguration regional-us-central1 – Bei regionalen Konfigurationen werden Daten in nur einer Region gespeichert, während sie bei multiregionalen Konfigurationen auf mehrere Regionen verteilt werden. Weitere Informationen dazu finden Sie unter Instanzen.
  • Knotenanzahl 1 – node_count entspricht der Anzahl der Bereitstellungs- und Speicherressourcen in der Instanz, die für Datenbanken zur Verfügung stehen. Weitere Informationen dazu finden Sie unter Knotenzahl.

Hier sollten Sie das sehen:

Creating instance...done.

Beispieldateien ansehen

Das Beispiel-Repository enthält ein Beispiel für die Verwendung von Cloud Spanner mit C++.

Sehen Sie in der Datei google/cloud/spanner/samples/samples.cc nach, wie Sie eine Datenbank erstellen und ein Datenbankschema ändern. In den Daten wird das auf der Seite Schema und Datenmodell angezeigte Beispielschema verwendet.

Datenbank erstellen

Erstellen Sie eine Datenbank mit dem Namen example-db in der Instanz test-instance, indem Sie Folgendes in der Befehlszeile ausführen:

bazel run //google/cloud/spanner/samples:samples -- \
    create-database $GCLOUD_PROJECT test-instance example-db

Hier sollten Sie das sehen:

Created database [projects/${GCLOUD_PROJECT}/instances/test-instance/databases/example-db]

Sie haben gerade eine Cloud Spanner-Datenbank erstellt. Die Datenbank wurde aus diesem Code erstellt:

void CreateDatabase(google::cloud::spanner::DatabaseAdminClient client,
                    std::string const& project_id,
                    std::string const& instance_id,
                    std::string const& database_id) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  std::vector<std::string> extra_statements;
  extra_statements.emplace_back(R"""(
      CREATE TABLE Singers (
          SingerId   INT64 NOT NULL,
          FirstName  STRING(1024),
          LastName   STRING(1024),
          SingerInfo BYTES(MAX)
      ) PRIMARY KEY (SingerId))""");
  extra_statements.emplace_back(R"""(
      CREATE TABLE Albums (
          SingerId     INT64 NOT NULL,
          AlbumId      INT64 NOT NULL,
          AlbumTitle   STRING(MAX)
      ) PRIMARY KEY (SingerId, AlbumId),
          INTERLEAVE IN PARENT Singers ON DELETE CASCADE)""");
  auto db = client.CreateDatabase(database, std::move(extra_statements)).get();
  if (!db) throw std::runtime_error(db.status().message());
  std::cout << "Database " << db->name() << " created.\n";
}

Mit dem Code werden außerdem die beiden Tabellen Singers und Albums für eine einfache Musikanwendung definiert. Die Tabellen werden im weiteren Verlauf dieser Seite verwendet. Sehen Sie sich das Beispielschema an, falls Sie es noch nicht getan haben.

Im nächsten Schritt werden Daten in die Datenbank geschrieben.

Datenbankclient erstellen

Bevor Sie Lese- oder Schreibvorgänge ausführen können, müssen Sie eine Client erstellen:

auto database = spanner::Database(project_id, instance_id, database_id);
auto connection = spanner::MakeConnection(database);
auto client = spanner::Client(connection);

Mit einem Client können Sie Transaktionen in einer Cloud Spanner-Datenbank lesen, schreiben, abfragen und ausführen. In der Regel erstellen Sie einen Client beim Start Ihrer Anwendung. Anschließend verwenden Sie diesen Client noch einmal zum Lesen, Schreiben und Ausführen von Transaktionen. Jeder Client verwendet Ressourcen in Cloud Spanner. Der Destruktor von Client bereinigt automatisch die Client-Ressourcen, einschließlich der Netzwerkverbindungen.

Weitere Informationen zu Client finden Sie in der Referenz zu C++ in Google Cloud Spanner.

Daten mit DML schreiben

Sie können Daten mit der Datenbearbeitungssprache (Data Manipulation Language, DML) in eine Lese-Schreib-Transaktion einfügen.

Für das Ausführen einer DML-Anweisung verwenden Sie die Funktion Client::ExecuteDml().

void DmlGettingStartedInsert(google::cloud::spanner::Client client) {
  using ::google::cloud::StatusOr;
  namespace spanner = ::google::cloud::spanner;

  auto commit_result = client.Commit(
      [&client](spanner::Transaction txn) -> StatusOr<spanner::Mutations> {
        auto insert = client.ExecuteDml(
            std::move(txn),
            spanner::SqlStatement(
                "INSERT INTO Singers (SingerId, FirstName, LastName) VALUES"
                " (12, 'Melissa', 'Garcia'),"
                " (13, 'Russell', 'Morales'),"
                " (14, 'Jacqueline', 'Long'),"
                " (15, 'Dylan', 'Shaw')"));
        if (!insert) return insert.status();
        return spanner::Mutations{};
      });
  if (!commit_result) {
    throw std::runtime_error(commit_result.status().message());
  }
  std::cout << "Insert was successful [spanner_dml_getting_started_insert]\n";
}

Führen Sie das Beispiel mit dem Argument getting-started-insert aus.

bazel run //google/cloud/spanner/samples:samples -- \
    getting-started-insert $GCLOUD_PROJECT test-instance example-db

Hier sollten Sie das sehen:

Insert was successful [spanner_dml_getting_started_insert]

Daten mit Mutationen schreiben

Sie können Daten auch mithilfe von Mutationen einfügen.

Daten werden mit einem Client-Objekt geschrieben. Mit der Funktion Client::Commit() wird eine Transaktion für Schreibvorgänge erstellt und festgeschrieben, die zu einem einzigen logischen Zeitpunkt in Spalten, Zeilen und Tabellen in einer Datenbank ausgeführt werden.

Dieser Code zeigt, wie die Daten mithilfe von Mutationen geschrieben werden:

void InsertData(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;
  auto insert_singers = spanner::InsertMutationBuilder(
                            "Singers", {"SingerId", "FirstName", "LastName"})
                            .EmplaceRow(1, "Marc", "Richards")
                            .EmplaceRow(2, "Catalina", "Smith")
                            .EmplaceRow(3, "Alice", "Trentor")
                            .EmplaceRow(4, "Lea", "Martin")
                            .EmplaceRow(5, "David", "Lomond")
                            .Build();

  auto insert_albums = spanner::InsertMutationBuilder(
                           "Albums", {"SingerId", "AlbumId", "AlbumTitle"})
                           .EmplaceRow(1, 1, "Total Junk")
                           .EmplaceRow(1, 2, "Go, Go, Go")
                           .EmplaceRow(2, 1, "Green")
                           .EmplaceRow(2, 2, "Forever Hold Your Peace")
                           .EmplaceRow(2, 3, "Terrified")
                           .Build();

  auto commit_result =
      client.Commit(spanner::Mutations{insert_singers, insert_albums});
  if (!commit_result) {
    throw std::runtime_error(commit_result.status().message());
  }
  std::cout << "Insert was successful [spanner_insert_data]\n";
}

Führen Sie das Beispiel mit dem Argument insert-data aus.

bazel run //google/cloud/spanner/samples:samples -- \
    insert-data $GCLOUD_PROJECT test-instance example-db

Hier sollten Sie das sehen:

Insert was successful [spanner_insert_data]

Daten mit SQL abfragen

Cloud Spanner unterstützt eine native SQL-Oberfläche zum Lesen von Daten, auf die Sie in der Befehlszeile mit dem gcloud-Befehlszeilentool oder programmatisch mit der Cloud Spanner-Clientbibliothek für C++ zugreifen können.

Über die Befehlszeile

Führen Sie die folgende SQL-Anweisung aus, damit Sie die Werte aller Spalten aus der Tabelle Albums lesen können:

gcloud spanner databases execute-sql example-db --instance=test-instance \
    --sql='SELECT SingerId, AlbumId, AlbumTitle FROM Albums'

Das Ergebnis sollte so aussehen:

SingerId AlbumId AlbumTitle
1        1       Total Junk
1        2       Go, Go, Go
2        1       Green
2        2       Forever Hold Your Peace
2        3       Terrified

Mit der Cloud Spanner-Clientbibliothek für C++

Als Alternative zum Ausführen einer SQL-Anweisung in der Befehlszeile können Sie die gleiche SQL-Anweisung programmgesteuert mithilfe der Cloud Spanner-Clientbibliothek für C++ ausführen.

Verwenden Sie die Funktion Client::ExecuteQuery(), um die SQL-Abfrage auszuführen. So geben Sie die Abfrage aus und greifen auf die Daten zu:

void QueryData(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;

  spanner::SqlStatement select("SELECT SingerId, LastName FROM Singers");
  using RowType = std::tuple<std::int64_t, std::string>;
  auto rows = client.ExecuteQuery(std::move(select));
  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 << "LastName: " << std::get<1>(*row) << "\n";
  }

  std::cout << "Query completed for [spanner_query_data]\n";
}

Führen Sie das Beispiel mit dem Argument query_data aus.

bazel run //google/cloud/spanner/samples:samples -- \
    query-data $GCLOUD_PROJECT test-instance example-db

Sie sollten folgendes Ergebnis sehen:

SingerId: 1     LastName: Richards
SingerId: 2     LastName: Smith
SingerId: 3     LastName: Trentor
SingerId: 4     LastName: Martin
SingerId: 5     LastName: Lomond
SingerId: 12    LastName: Garcia
SingerId: 13    LastName: Morales
SingerId: 14    LastName: Long
SingerId: 15    LastName: Shaw

Abfrage mit einem SQL-Parameter

Sie können mithilfe von unterstützten SQL-Typen benutzerdefinierte Werte in SQL-Anweisungen einfügen.

Im Folgenden finden Sie ein Beispiel für die Verwendung von @lastName als Parameter in der WHERE-Klausel zum Abfragen von Datensätzen, die einen bestimmten Wert für LastName enthalten.

void QueryWithParameter(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;

  spanner::SqlStatement select(
      "SELECT SingerId, FirstName, LastName FROM Singers"
      " WHERE LastName = @last_name",
      {{"last_name", spanner::Value("Garcia")}});
  using RowType = std::tuple<std::int64_t, std::string, std::string>;
  auto rows = client.ExecuteQuery(std::move(select));
  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) << "\t";
    std::cout << "LastName: " << std::get<2>(*row) << "\n";
  }

  std::cout << "Query completed for [spanner_query_with_parameter]\n";
}

Führen Sie das Beispiel mit dem Befehl "query-with-parameter" aus.

bazel run //google/cloud/spanner/samples:samples -- \
    query-with-parameter $GCLOUD_PROJECT test-instance example-db

Sie sollten folgendes Ergebnis sehen:

SingerId: 12    FirstName: Melissa      LastName: Garcia

Daten mit der Lese-API auslesen

Neben der SQL-Schnittstelle unterstützt Cloud Spanner auch eine Leseschnittstelle.

Mit der Funktion Client::Read() können Sie Zeilen aus der Datenbank lesen. Mit dem Objekt KeySet können Sie eine Sammlung der zu lesenden Schlüssel und Schlüsselbereiche definieren.

So lesen Sie die Daten aus:

void ReadData(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;

  auto rows = client.Read("Albums", google::cloud::spanner::KeySet::All(),
                          {"SingerId", "AlbumId", "AlbumTitle"});
  using RowType = std::tuple<std::int64_t, 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 << "AlbumId: " << std::get<1>(*row) << "\t";
    std::cout << "AlbumTitle: " << std::get<2>(*row) << "\n";
  }

  std::cout << "Read completed for [spanner_read_data]\n";
}

Führen Sie das Beispiel mit dem Argument read-data aus.

bazel run //google/cloud/spanner/samples:samples -- \
    read-data $GCLOUD_PROJECT test-instance example-db

Die Ausgabe sollte etwa so aussehen:

SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk
SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go
SingerId: 2, AlbumId: 1, AlbumTitle: Green
SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace
SingerId: 2, AlbumId: 3, AlbumTitle: Terrified

Datenbankschema aktualisieren

Beispiel: Sie müssen eine neue Spalte namens MarketingBudget zur Tabelle Albums hinzufügen. Damit einer vorhandenen Tabelle eine neue Spalte hinzugefügt werden kann, muss das Datenbankschema aktualisiert werden. Cloud Spanner unterstützt Schemaaktualisierungen für Datenbanken, ohne dass die Traffic-Bereitstellung unterbrochen werden muss. Bei einer Schemaaktualisierung muss die Datenbank nicht offline geschaltet und es müssen keine ganzen Tabellen oder Spalten gesperrt werden. Sie können während der Aktualisierung weiter Daten in die Datenbank schreiben. Weitere Informationen zu unterstützten Schemaaktualisierungen und zur Leistung während der Schemaänderung finden Sie unter Schemaaktualisierungen.

Spalte hinzufügen

Sie können eine Spalte in der Befehlszeile mithilfe des gcloud-Befehlszeilentools oder programmgesteuert mithilfe der Cloud Spanner-Clientbibliothek für C++ hinzufügen.

Über die Befehlszeile

Verwenden Sie den folgenden Befehl ALTER TABLE, um die neue Spalte zur Tabelle hinzuzufügen:

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='ALTER TABLE Albums ADD COLUMN MarketingBudget INT64'

Hier sollten Sie das sehen:

Schema updating...done.

Mit der Cloud Spanner-Clientbibliothek für C++

Verwenden Sie die Funktion DatabaseAdminClient::UpdateDatabase(), um das Schema zu ändern.

void AddColumn(google::cloud::spanner::DatabaseAdminClient client,
               std::string const& project_id, std::string const& instance_id,
               std::string const& database_id) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  auto metadata =
      client
          .UpdateDatabase(
              database, {"ALTER TABLE Albums ADD COLUMN MarketingBudget INT64"})
          .get();
  if (!metadata) throw std::runtime_error(metadata.status().message());
  std::cout << "Added MarketingBudget column\n";
}

Führen Sie das Beispiel mit dem Befehl add-column aus.

bazel run //google/cloud/spanner/samples:samples -- \
    add-column $GCLOUD_PROJECT test-instance example-db

Es sollte dann Folgendes angezeigt werden:

Added MarketingBudget column

Daten in die neue Spalte schreiben

Mit dem folgenden Code werden Daten in die neue Spalte geschrieben. Er legt für MarketingBudget den Wert 100000 für den Zeilenschlüssel fest, der durch Albums(1, 1) angegeben wird, und 500000 für den Zeilenschlüssel, der durch Albums(2, 2) angegeben wird.

void UpdateData(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;
  auto commit_result = client.Commit(spanner::Mutations{
      spanner::UpdateMutationBuilder("Albums",
                                     {"SingerId", "AlbumId", "MarketingBudget"})
          .EmplaceRow(1, 1, 100000)
          .EmplaceRow(2, 2, 500000)
          .Build()});
  if (!commit_result) {
    throw std::runtime_error(commit_result.status().message());
  }
  std::cout << "Update was successful [spanner_update_data]\n";
}

Führen Sie das Beispiel mit dem Argument update-data aus.

bazel run //google/cloud/spanner/samples:samples -- \
    update-data $GCLOUD_PROJECT test-instance example-db

Sie können auch eine SQL-Abfrage oder einen Leseaufruf ausführen, um die Werte abzurufen, die Sie gerade geschrieben haben.

Mit diesem Code können Sie die Abfrage ausführen:

void QueryNewColumn(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;

  spanner::SqlStatement select(
      "SELECT SingerId, AlbumId, MarketingBudget FROM Albums");

  using RowType =
      std::tuple<std::int64_t, std::int64_t, absl::optional<std::int64_t>>;
  auto rows = client.ExecuteQuery(std::move(select));
  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 << "AlbumId: " << std::get<1>(*row) << "\t";
    auto marketing_budget = std::get<2>(*row);
    if (marketing_budget) {
      std::cout << "MarketingBudget: " << *marketing_budget << "\n";
    } else {
      std::cout << "MarketingBudget: NULL\n";
    }
  }
  std::cout << "Read completed for [spanner_read_data_with_new_column]\n";
}

Für diese Abfrage führen Sie das Beispiel mit dem Argument query-new-column aus.

bazel run //google/cloud/spanner/samples:samples -- \
    query-new-column $GCLOUD_PROJECT test-instance example-db

Hier sollten Sie das sehen:

SingerId: 1 AlbumId: 1  MarketingBudget: 100000
SingerId: 1 AlbumId: 2  MarketingBudget: NULL
SingerId: 2 AlbumId: 1  MarketingBudget: NULL
SingerId: 2 AlbumId: 2  MarketingBudget: 500000
SingerId: 2 AlbumId: 3  MarketingBudget: NULL

Daten aktualisieren

Sie können Daten mit DML in einer Lese-Schreib-Transaktion aktualisieren.

Für das Ausführen einer DML-Anweisung verwenden Sie die Funktion Client::ExecuteDml().

void DmlGettingStartedUpdate(google::cloud::spanner::Client client) {
  using ::google::cloud::StatusOr;
  namespace spanner = ::google::cloud::spanner;

  // A helper to read the budget for the given album and singer.
  auto get_budget = [&](spanner::Transaction txn, std::int64_t album_id,
                        std::int64_t singer_id) -> StatusOr<std::int64_t> {
    auto key = spanner::KeySet().AddKey(spanner::MakeKey(album_id, singer_id));
    auto rows = client.Read(std::move(txn), "Albums", key, {"MarketingBudget"});
    using RowType = std::tuple<absl::optional<std::int64_t>>;
    auto row = spanner::GetSingularRow(spanner::StreamOf<RowType>(rows));
    if (!row) return row.status();
    auto const budget = std::get<0>(*row);
    return budget ? *budget : 0;
  };

  // A helper to update the budget for the given album and singer.
  auto update_budget = [&](spanner::Transaction txn, std::int64_t album_id,
                           std::int64_t singer_id, std::int64_t budget) {
    auto sql = spanner::SqlStatement(
        "UPDATE Albums SET MarketingBudget = @AlbumBudget "
        "WHERE SingerId = @SingerId AND AlbumId = @AlbumId",
        {{"AlbumBudget", spanner::Value(budget)},
         {"AlbumId", spanner::Value(album_id)},
         {"SingerId", spanner::Value(singer_id)}});
    return client.ExecuteDml(std::move(txn), std::move(sql));
  };

  auto const transfer_amount = 20000;
  auto commit_result = client.Commit(
      [&](spanner::Transaction const& txn) -> StatusOr<spanner::Mutations> {
        auto budget1 = get_budget(txn, 1, 1);
        if (!budget1) return budget1.status();
        if (*budget1 < transfer_amount) {
          return google::cloud::Status(
              google::cloud::StatusCode::kUnknown,
              "cannot transfer " + std::to_string(transfer_amount) +
                  " from budget of " + std::to_string(*budget1));
        }
        auto budget2 = get_budget(txn, 2, 2);
        if (!budget2) return budget2.status();
        auto update = update_budget(txn, 1, 1, *budget1 - transfer_amount);
        if (!update) return update.status();
        update = update_budget(txn, 2, 2, *budget2 + transfer_amount);
        if (!update) return update.status();
        return spanner::Mutations{};
      });
  if (!commit_result) {
    throw std::runtime_error(commit_result.status().message());
  }
  std::cout << "Update was successful [spanner_dml_getting_started_update]\n";
}

Führen Sie das Beispiel mit dem Argument getting-started-update aus.

bazel run //google/cloud/spanner/samples:samples -- \
    getting-started-update $GCLOUD_PROJECT test-instance example-db

Hier sollten Sie das sehen:

Update was successful [spanner_dml_getting_started_update]

Sekundären Index verwenden

Beispiel: Sie möchten alle Zeilen aus Albums abrufen, deren Wert für AlbumTitle in einem bestimmten Bereich liegen. Sie könnten dazu alle Werte aus der Spalte AlbumTitle mit einer SQL-Anweisung oder einem Leseaufruf lesen und dann die Zeilen verwerfen, die die Kriterien nicht erfüllen. Dieser vollständige Tabellenscan wäre jedoch sehr kostspielig, insbesondere bei Tabellen mit vielen Zeilen. Stattdessen können Sie einen sekundären Index für die Tabelle erstellen und damit das Abrufen von Zeilen beim Suchen über Spalten mit nicht primärem Schlüssel beschleunigen.

Damit ein sekundärer Index einer vorhandenen Tabelle hinzugefügt werden kann, muss das Schema aktualisiert werden. Wie bei anderen Schemaaktualisierungen kann mit Cloud Spanner ein Index hinzugefügt werden, ohne dass die Traffic-Bereitstellung unterbrochen werden muss. Cloud Spanner verwendet dann automatisch die vorhandenen Daten, um einen Backfill für den Index auszuführen. Backfills können einige Minuten dauern. Sie müssen aber die Datenbank nicht offline schalten und können während des Vorgangs weiter in die indexierten Tabellen schreiben. Weitere Informationen finden Sie unter Index-Backfill.

Nachdem Sie einen sekundären Index hinzugefügt haben, verwendet Cloud Spanner diesen automatisch für SQL-Abfragen, die mit dem Index sehr wahrscheinlich schneller ausgeführt werden. Wenn Sie die Leseschnittstelle verwenden, müssen Sie den Index angeben, den Sie nutzen möchten.

Sekundären Index hinzufügen

Sie können einen Index in der Befehlszeile mithilfe des gcloud-Befehlszeilentools oder programmgesteuert mithilfe der Cloud Spanner-Clientbibliothek für C++ hinzufügen.

Über die Befehlszeile

Verwenden Sie den folgenden Befehl CREATE INDEX, um der Datenbank einen Index hinzuzufügen:

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)'

Hier sollten Sie das sehen:

Schema updating...done.

Mit der Cloud Spanner-Clientbibliothek für C++

Mit der Funktion DatabaseAdminClient::UpdateDatabase() fügen Sie einen Index hinzu:

void AddIndex(google::cloud::spanner::DatabaseAdminClient client,
              std::string const& project_id, std::string const& instance_id,
              std::string const& database_id) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  auto metadata =
      client
          .UpdateDatabase(
              database,
              {"CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)"})
          .get();
  if (!metadata) throw std::runtime_error(metadata.status().message());
  std::cout << "`AlbumsByAlbumTitle` Index successfully added, new DDL:\n"
            << metadata->DebugString();
}

Führen Sie das Beispiel mit dem Argument add-index aus.

bazel run //google/cloud/spanner/samples:samples -- \
    add-index $GCLOUD_PROJECT test-instance example-db

Das Hinzufügen eines Index kann einige Minuten dauern. Nachdem der Index hinzugefügt wurde, sollte die Ausgabe in etwa so aussehen:

`AlbumsByAlbumTitle` Index successfully added, new DDL:
database: "projects/$GCLOUD_PROJECT/instances/test-instance/databases/example-db"
statements: "CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)"
commit_timestamps {
  seconds: 1581011550
  nanos: 531102000
}

Mit dem Index auslesen

Für SQL-Abfragen verwendet Cloud Spanner automatisch einen geeigneten Index. In der Leseschnittstelle müssen Sie den Index in Ihrer Anfrage angeben.

Für die Verwendung des Index in der Leseschnittstelle nutzen Sie Client::Read(). Dieser Vorgang dient zum Lesen von null oder mehr Zeilen aus einer Datenbank mithilfe eines Index.

Mit dem folgenden Code werden alle Spalten AlbumId und AlbumTitle aus dem Index AlbumsByAlbumTitle abgerufen.

void ReadDataWithIndex(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;

  spanner::ReadOptions read_options;
  read_options.index_name = "AlbumsByAlbumTitle";
  auto rows = client.Read("Albums", google::cloud::spanner::KeySet::All(),
                          {"AlbumId", "AlbumTitle"}, read_options);
  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 << "AlbumId: " << std::get<0>(*row) << "\t";
    std::cout << "AlbumTitle: " << std::get<1>(*row) << "\n";
  }
  std::cout << "Read completed for [spanner_read_data_with_index]\n";
}

Führen Sie das Beispiel mit dem Argument read-data-with-index aus.

bazel run //google/cloud/spanner/samples:samples -- \
    read-data-with-index $GCLOUD_PROJECT test-instance example-db

Hier sollten Sie das sehen:

AlbumId: 2  AlbumTitle: Forever Hold Your Peace
AlbumId: 2  AlbumTitle: Go, Go, Go
AlbumId: 1  AlbumTitle: Green
AlbumId: 3  AlbumTitle: Terrified
AlbumId: 1  AlbumTitle: Total Junk

Index mit einer STORING-Klausel hinzufügen

Vielleicht haben Sie bemerkt, dass im obigen Beispiel die Spalte MarketingBudget nicht gelesen wird. Die Leseschnittstelle von Cloud Spanner unterstützt nicht die Möglichkeit, einen Index mit einer Datentabelle zu verbinden, um Werte zu suchen, die nicht im Index gespeichert sind.

Erstellen Sie eine alternative Definition von AlbumsByAlbumTitle, die eine Kopie von MarketingBudget im Index speichert.

Über die Befehlszeile

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget)'

Das Hinzufügen eines Index kann einige Minuten dauern. Nachdem der Index hinzugefügt wurde, sollten Sie das sehen:

Schema updating...done.

Mit der Cloud Spanner-Clientbibliothek für C++

Mit der Funktion DatabaseAdminClient::UpdateDatabase() fügen Sie einen Index mit einer STORING-Klausel hinzu:

void AddStoringIndex(google::cloud::spanner::DatabaseAdminClient client,
                     std::string const& project_id,
                     std::string const& instance_id,
                     std::string const& database_id) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  auto metadata = client
                      .UpdateDatabase(database, {R"""(
                        CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle)
                            STORING (MarketingBudget))"""})
                      .get();
  if (!metadata) throw std::runtime_error(metadata.status().message());
  std::cout << "`AlbumsByAlbumTitle2` Index successfully added, new DDL:\n"
            << metadata->DebugString();
}

Führen Sie das Beispiel mit dem Argument add-storing-index aus.

bazel run //google/cloud/spanner/samples:samples -- \
    add-storing-index $GCLOUD_PROJECT test-instance example-db

Die Ausgabe sollte etwa so aussehen:

`AlbumsByAlbumTitle2` Index successfully added, new DDL:
database: "projects/$GCLOUD_PROJECT/instances/test-instance/databases/example-db"
statements: "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget)"
commit_timestamps {
  seconds: 1581012328
  nanos: 416682000
}

Sie können jetzt einen Lesevorgang ausführen, der die Spalten AlbumId, AlbumTitle und MarketingBudget aus dem Index AlbumsByAlbumTitle2 abruft:

Lesen Sie die Daten mit dem von Ihnen erstellten Speicherindex. Führen Sie dazu eine Abfrage aus, in der der Index explizit angegeben wird:

void ReadDataWithStoringIndex(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;

  spanner::ReadOptions read_options;
  read_options.index_name = "AlbumsByAlbumTitle2";
  auto rows =
      client.Read("Albums", google::cloud::spanner::KeySet::All(),
                  {"AlbumId", "AlbumTitle", "MarketingBudget"}, read_options);
  using RowType =
      std::tuple<std::int64_t, std::string, absl::optional<std::int64_t>>;
  for (auto const& row : spanner::StreamOf<RowType>(rows)) {
    if (!row) throw std::runtime_error(row.status().message());
    std::cout << "AlbumId: " << std::get<0>(*row) << "\t";
    std::cout << "AlbumTitle: " << std::get<1>(*row) << "\t";
    auto marketing_budget = std::get<2>(*row);
    if (marketing_budget) {
      std::cout << "MarketingBudget: " << *marketing_budget << "\n";
    } else {
      std::cout << "MarketingBudget: NULL\n";
    }
  }
  std::cout << "Read completed for [spanner_read_data_with_storing_index]\n";
}

Führen Sie das Beispiel mit dem Argument read-data-with-storing-index aus.

bazel run //google/cloud/spanner/samples:samples -- \
    read-data-with-storing-index $GCLOUD_PROJECT test-instance example-db

Die Ausgabe sollte etwa so aussehen:

AlbumId: 2  AlbumTitle: Forever Hold Your Peace MarketingBudget: 520000
AlbumId: 2  AlbumTitle: Go, Go, Go  MarketingBudget: NULL
AlbumId: 1  AlbumTitle: Green   MarketingBudget: NULL
AlbumId: 3  AlbumTitle: Terrified   MarketingBudget: NULL
AlbumId: 1  AlbumTitle: Total Junk  MarketingBudget: 80000

Daten mit schreibgeschützten Transaktionen abrufen

Angenommen, Sie möchten mehr als einen Lesevorgang mit demselben Zeitstempel ausführen. Bei schreibgeschützten Transaktionen wird ein gleichbleibendes Präfix des Commit-Verlaufs der Transaktionen beibehalten, damit die Anwendung immer konsistente Daten erhält. Der Typ Transaction wird für alle Arten von Transaktionen verwendet. Verwenden Sie die Factory-Funktion MakeReadOnlyTransaction(), um eine schreibgeschützte Transaktion zu erstellen.

So werden eine Abfrage und ein Lesevorgang in derselben schreibgeschützten Transaktion ausgeführt:

void ReadOnlyTransaction(google::cloud::spanner::Client client) {
  namespace spanner = ::google::cloud::spanner;
  auto read_only = spanner::MakeReadOnlyTransaction();

  spanner::SqlStatement select(
      "SELECT SingerId, AlbumId, AlbumTitle FROM Albums");
  using RowType = std::tuple<std::int64_t, std::int64_t, std::string>;

  // Read#1.
  auto rows1 = client.ExecuteQuery(read_only, select);
  std::cout << "Read 1 results\n";
  for (auto const& row : spanner::StreamOf<RowType>(rows1)) {
    if (!row) throw std::runtime_error(row.status().message());
    std::cout << "SingerId: " << std::get<0>(*row)
              << " AlbumId: " << std::get<1>(*row)
              << " AlbumTitle: " << std::get<2>(*row) << "\n";
  }
  // Read#2. Even if changes occur in-between the reads the transaction ensures
  // that Read #1 and Read #2 return the same data.
  auto rows2 = client.ExecuteQuery(read_only, select);
  std::cout << "Read 2 results\n";
  for (auto const& row : spanner::StreamOf<RowType>(rows2)) {
    if (!row) throw std::runtime_error(row.status().message());
    std::cout << "SingerId: " << std::get<0>(*row)
              << " AlbumId: " << std::get<1>(*row)
              << " AlbumTitle: " << std::get<2>(*row) << "\n";
  }
}

Führen Sie das Beispiel mit dem Argument read-only-transaction aus.

bazel run //google/cloud/spanner/samples:samples -- \
    read-only-transaction $GCLOUD_PROJECT test-instance example-db

Die Ausgabe sollte etwa so aussehen:

Read 1 results
SingerId: 2 AlbumId: 2 AlbumTitle: Forever Hold Your Peace
SingerId: 1 AlbumId: 2 AlbumTitle: Go, Go, Go
SingerId: 2 AlbumId: 1 AlbumTitle: Green
SingerId: 2 AlbumId: 3 AlbumTitle: Terrified
SingerId: 1 AlbumId: 1 AlbumTitle: Total Junk
Read 2 results
SingerId: 2 AlbumId: 2 AlbumTitle: Forever Hold Your Peace
SingerId: 1 AlbumId: 2 AlbumTitle: Go, Go, Go
SingerId: 2 AlbumId: 1 AlbumTitle: Green
SingerId: 2 AlbumId: 3 AlbumTitle: Terrified
SingerId: 1 AlbumId: 1 AlbumTitle: Total Junk

Clean-up

Löschen Sie die Datenbank und die erstellte Instanz, um zu vermeiden, dass Ihrem Cloud-Rechnungskonto die in dieser Anleitung verwendeten Ressourcen in Rechnung gestellt werden.

Datenbank löschen

Wenn Sie eine Instanz löschen, werden alle darin enthaltenen Datenbanken automatisch gelöscht. In diesem Schritt wird gezeigt, wie eine Datenbank gelöscht wird, ohne eine Instanz zu löschen (dabei fallen weiterhin Gebühren für die Instanz an).

Über die Befehlszeile

gcloud spanner databases delete example-db --instance=test-instance

Mit der Cloud Console

  1. Rufen Sie in der Google Cloud Console die Seite Cloud Spanner-Instanzen auf.

    Zur Seite "VM-Instanzen"

  2. Klicken Sie auf die Instanz.

  3. Klicken Sie auf die Datenbank, die Sie löschen möchten.

  4. Klicken Sie auf der Seite Datenbankdetails auf Löschen.

  5. Bestätigen Sie, dass die Datenbank gelöscht werden soll, und klicken Sie auf Löschen.

Instanz löschen

Beim Löschen einer Instanz werden alle Datenbanken, die in der Instanz erstellt wurden, automatisch gelöscht.

Über die Befehlszeile

gcloud spanner instances delete test-instance

Mit der Cloud Console

  1. Rufen Sie in der Google Cloud Console die Seite Cloud Spanner-Instanzen auf.

    Zur Seite "VM-Instanzen"

  2. Klicken Sie auf die Instanz.

  3. Klicken Sie auf Löschen.

  4. Bestätigen Sie, dass die Instanz gelöscht werden soll, und klicken Sie auf Löschen.

Weitere Informationen

  • Über eine VM-Instanz auf Cloud Spanner zugreifen: Erstellen Sie eine VM-Instanz mit Zugriff auf die Cloud Spanner-Datenbank.
  • Anmeldedaten für die Autorisierung und Authentifizierung: Siehe Erste Schritte bei der Authentifizierung
  • Cloud Spanner-Konzepte