1. Übersicht
Google Cloud Spanner ist ein vollständig verwalteter, horizontal skalierbarer, global verteilter relationaler Datenbankdienst, der ACID-Transaktionen und SQL-Semantik bietet, ohne auf Leistung und Hochverfügbarkeit zu verzichten.
In diesem Lab erfahren Sie, wie Sie eine Cloud Spanner-Instanz einrichten. Sie führen die Schritte zum Erstellen einer Datenbank und eines Schemas aus, die für eine Gaming-Bestenliste verwendet werden können. Zuerst erstellen Sie eine Spielertabelle zur Speicherung von Spielerinformationen und eine Punktzahltabelle, in der die Punktzahlen der Spieler gespeichert werden.
Als Nächstes füllen Sie die Tabellen mit Beispieldaten. Am Ende des Labs führen Sie einige Top-10-Beispielabfragen aus und löschen schließlich die Instanz, um Ressourcen freizugeben.
Aufgaben in diesem Lab
- Cloud Spanner-Instanz einrichten
- Datenbank und Tabellen erstellen
- So verwenden Sie eine Commit-Zeitstempelspalte.
- Daten in eine Cloud Spanner-Datenbanktabelle mit Zeitstempeln laden.
- Anleitung zum Abfragen Ihrer Cloud Spanner-Datenbank.
- Cloud Spanner-Instanz löschen
Voraussetzungen
Wie möchten Sie diese Anleitung nutzen?
<ph type="x-smartling-placeholder">Wie würden Sie Ihre Erfahrung mit der Google Cloud Platform bewerten?
<ph type="x-smartling-placeholder">2. Einrichtung und Anforderungen
Umgebung für das selbstbestimmte Lernen einrichten
Wenn Sie noch kein Google-Konto (Gmail oder Google Apps) haben, müssen Sie eines erstellen. Melden Sie sich in der Google Cloud Platform Console ( console.cloud.google.com) an und erstellen Sie ein neues Projekt.
Wenn Sie bereits ein Projekt haben, klicken Sie auf das Drop-down-Menü für die Projektauswahl oben links in der Konsole:
und klicken Sie auf „NEUES PROJEKT“, Schaltfläche zum Erstellen eines neuen Projekts:
Wenn Sie noch kein Projekt haben, sollten Sie ein Dialogfeld wie dieses sehen, um Ihr erstes zu erstellen:
Im nachfolgenden Dialog zur Projekterstellung können Sie die Details Ihres neuen Projekts eingeben:
Denken Sie an die Projekt-ID. Dies ist ein eindeutiger Name für alle Google Cloud-Projekte. Der oben angegebene Name ist bereits vergeben und funktioniert leider nicht für Sie. Sie wird in diesem Codelab später als PROJECT_ID
bezeichnet.
Falls noch nicht geschehen, müssen Sie als Nächstes in der Developers Console die Abrechnung aktivieren, um Google Cloud-Ressourcen nutzen und die Cloud Spanner API aktivieren zu können.
Dieses Codelab sollte nicht mehr als ein paar Euro kosten. Wenn Sie sich jedoch dazu entschließen, mehr Ressourcen zu verwenden oder diese weiter auszuführen (siehe Abschnitt „Bereinigen“ am Ende dieses Dokuments), Die Preise für Google Cloud Spanner finden Sie hier.
Neue Google Cloud Platform-Nutzer haben Anspruch auf eine kostenlose Testversion mit 300$Guthaben, wodurch das Codelab in der Regel kostenlos sein sollte.
Google Cloud Shell einrichten
Sie können Google Cloud und Spanner über Ihren Laptop aus der Ferne bedienen. In diesem Codelab verwenden wir jedoch Google Cloud Shell, eine Befehlszeilenumgebung, die in der Cloud ausgeführt wird.
Diese Debian-basierte virtuelle Maschine verfügt über alle erforderlichen Entwicklungstools. Es bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und wird in Google Cloud ausgeführt. Dadurch werden die Netzwerkleistung und die Authentifizierung erheblich verbessert. Für dieses Codelab benötigen Sie also nur einen Browser – ja, er funktioniert auf Chromebooks.
- Klicken Sie einfach auf Cloud Shell aktivieren , um Cloud Shell über die Cloud Console zu aktivieren. Die Bereitstellung und Verbindung mit der Umgebung dauert einen Moment.
Sobald Sie mit Cloud Shell verbunden sind, sollten Sie sehen, dass Sie bereits authentifiziert sind und dass das Projekt bereits auf Ihre PROJECT_ID
eingestellt ist.
gcloud auth list
Befehlsausgabe
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Befehlsausgabe
[core] project = <PROJECT_ID>
Sollte das Projekt aus irgendeinem Grund nicht eingerichtet sein, geben Sie einfach den folgenden Befehl ein:
gcloud config set project <PROJECT_ID>
Du suchst dein Gerät (PROJECT_ID
)? Sehen Sie nach, welche ID Sie bei den Einrichtungsschritten verwendet haben, oder rufen Sie sie im Dashboard der Cloud Console auf:
Cloud Shell legt außerdem standardmäßig einige Umgebungsvariablen fest, die bei der Ausführung zukünftiger Befehle nützlich sein können.
echo $GOOGLE_CLOUD_PROJECT
Befehlsausgabe
<PROJECT_ID>
- Legen Sie schließlich die Standardzone und die Projektkonfiguration fest.
gcloud config set compute/zone us-central1-f
Sie können verschiedene Zonen auswählen. Weitere Informationen finden Sie unter Regionen und Zonen.
Zusammenfassung
In diesem Schritt richten Sie Ihre Umgebung ein.
Nächstes Thema
Als Nächstes richten Sie eine Cloud Spanner-Instanz ein.
3. Cloud Spanner-Instanz einrichten
In diesem Schritt richten wir unsere Cloud Spanner-Instanz für dieses Codelab ein. Suchen Sie im linken Hamburger-Menü nach dem Spanner-Eintrag oder drücken Sie „/“, um nach Spanner zu suchen und geben Sie „Spanner“ ein
Klicken Sie als Nächstes auf und füllen Sie das Formular aus. Geben Sie dazu den Instanznamen cloudspanner-leaderboard für Ihre Instanz ein, wählen Sie eine Konfiguration aus (wählen Sie eine regionale Instanz aus) und legen Sie die Anzahl der Knoten fest. Für dieses Codelab benötigen wir nur einen Knoten. Für Produktionsinstanzen und zur Einhaltung des Cloud Spanner-SLA müssen Sie mindestens drei Knoten in Ihrer Cloud Spanner-Instanz ausführen.
Klicken Sie abschließend auf „Erstellen“. und innerhalb von Sekunden steht eine Cloud Spanner-Instanz zur Verfügung.
Im nächsten Schritt erstellen wir mithilfe der C#-Clientbibliothek eine Datenbank und ein Schema in der neuen Instanz.
4. Datenbank und Schema erstellen
In diesem Schritt erstellen wir die Beispieldatenbank und das Schema.
Erstellen wir mit der C#-Clientbibliothek zwei Tabellen. eine Spielertabelle mit Spielerinformationen und eine Punktzahltabelle zum Speichern der Punktzahlen der Spieler Gehen Sie dazu die Schritte zum Erstellen einer C#-Konsolenanwendung in Cloud Shell durch.
Klonen Sie zuerst den Beispielcode für dieses Codelab aus GitHub. Geben Sie dazu den folgenden Befehl in Cloud Shell ein:
git clone https://github.com/GoogleCloudPlatform/dotnet-docs-samples.git
Wechseln Sie dann in das Verzeichnis „applications“ Verzeichnis, in dem Sie Ihre Anwendung erstellen.
cd dotnet-docs-samples/applications/
Der gesamte Code, der für dieses Codelab erforderlich ist, befindet sich im vorhandenen dotnet-docs-samples/applications/leaderboard
-Verzeichnis als ausführbare C#-Anwendung mit dem Namen Leaderboard
. Sie dient als Referenz, während Sie das Codelab durchlaufen. Wir werden ein neues Verzeichnis erstellen und schrittweise eine Kopie der Leaderboard-Anwendung erstellen.
Erstellen Sie ein neues Verzeichnis mit dem Namen „codelab“. für die Anwendung und wechseln Sie mit dem folgenden Befehl in das entsprechende Verzeichnis:
mkdir codelab && cd $_
Eine neue .NET-C#-Konsolenanwendung namens "Leaderboard" erstellen mit dem folgenden Befehl:
dotnet new console -n Leaderboard
Mit diesem Befehl wird eine einfache Konsolenanwendung erstellt, die aus zwei primären Dateien besteht: der Projektdatei Leaderboard.csproj
und der Programmdatei Program.cs
.
und führen es aus. Wechseln Sie in das neu erstellte Leaderboard-Verzeichnis, in dem sich die Anwendung befindet:
cd Leaderboard
Geben Sie dann den folgenden Befehl ein, um ihn auszuführen.
dotnet run
Sie sollten die Anwendungsausgabe „Hello World!“ sehen.
Aktualisieren wir nun unsere Konsolen-App, indem wir Program.cs
so bearbeiten, dass mithilfe der C#-Spanner-Clientbibliothek eine Bestenliste erstellt wird, die aus zwei Tabellen für Spieler und Punktzahlen besteht. Sie können dies direkt im Cloud Shell-Editor tun:
Öffnen Sie den Cloud Shell-Editor, indem Sie auf das unten hervorgehobene Symbol klicken:
Öffnen Sie als Nächstes die Datei Program.cs
im Cloud Shell-Editor und ersetzen Sie den vorhandenen Code der Datei durch den Code, der zum Erstellen der Datenbank leaderboard
und der Tabellen Players
und Scores
erforderlich ist. Fügen Sie dazu den folgenden C#-Anwendungscode in die Datei Program.cs
ein:
using System;
using System.Threading.Tasks;
using Google.Cloud.Spanner.Data;
using CommandLine;
namespace GoogleCloudSamples.Leaderboard
{
[Verb("create", HelpText = "Create a sample Cloud Spanner database "
+ "along with sample 'Players' and 'Scores' tables in your project.")]
class CreateOptions
{
[Value(0, HelpText = "The project ID of the project to use "
+ "when creating Cloud Spanner resources.", Required = true)]
public string projectId { get; set; }
[Value(1, HelpText = "The ID of the instance where the sample database "
+ "will be created.", Required = true)]
public string instanceId { get; set; }
[Value(2, HelpText = "The ID of the sample database to create.",
Required = true)]
public string databaseId { get; set; }
}
public class Program
{
enum ExitCode : int
{
Success = 0,
InvalidParameter = 1,
}
public static object Create(string projectId,
string instanceId, string databaseId)
{
var response =
CreateAsync(projectId, instanceId, databaseId);
Console.WriteLine("Waiting for operation to complete...");
response.Wait();
Console.WriteLine($"Operation status: {response.Status}");
Console.WriteLine($"Created sample database {databaseId} on "
+ $"instance {instanceId}");
return ExitCode.Success;
}
public static async Task CreateAsync(
string projectId, string instanceId, string databaseId)
{
// Initialize request connection string for database creation.
string connectionString =
$"Data Source=projects/{projectId}/instances/{instanceId}";
using (var connection = new SpannerConnection(connectionString))
{
string createStatement = $"CREATE DATABASE `{databaseId}`";
string[] createTableStatements = new string[] {
// Define create table statement for Players table.
@"CREATE TABLE Players(
PlayerId INT64 NOT NULL,
PlayerName STRING(2048) NOT NULL
) PRIMARY KEY(PlayerId)",
// Define create table statement for Scores table.
@"CREATE TABLE Scores(
PlayerId INT64 NOT NULL,
Score INT64 NOT NULL,
Timestamp TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp=true)
) PRIMARY KEY(PlayerId, Timestamp),
INTERLEAVE IN PARENT Players ON DELETE NO ACTION" };
// Make the request.
var cmd = connection.CreateDdlCommand(
createStatement, createTableStatements);
try
{
await cmd.ExecuteNonQueryAsync();
}
catch (SpannerException e) when
(e.ErrorCode == ErrorCode.AlreadyExists)
{
// OK.
}
}
}
public static int Main(string[] args)
{
var verbMap = new VerbMap<object>();
verbMap
.Add((CreateOptions opts) => Create(
opts.projectId, opts.instanceId, opts.databaseId))
.NotParsedFunc = (err) => 1;
return (int)verbMap.Run(args);
}
}
}
Zur Verdeutlichung des Programmcodes hier ein Diagramm des Programms mit den beschrifteten Hauptkomponenten:
Mit der Datei Program.cs
im Verzeichnis dotnet-docs-samples/applications/leaderboard/step4
können Sie sich ein Beispiel dafür ansehen, wie Ihre Datei Program.cs
aussehen sollte, nachdem Sie den Code zum Aktivieren des Befehls create
hinzugefügt haben.
Verwenden Sie als Nächstes den Cloud Shell-Editor, um die Projektdatei Leaderboard.csproj
des Programms zu öffnen und zu bearbeiten. Aktualisieren Sie sie in den folgenden Code. Speichern Sie alle Änderungen mithilfe der Option "Datei" des Cloud Shell-Editors.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Google.Cloud.Spanner.Data" Version="3.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\commandlineutil\Lib\CommandLineUtil.csproj" />
</ItemGroup>
</Project>
Durch diese Änderung wurde ein Verweis auf das C# Spanner Nuget-Paket hinzugefügt, das für die Interaktion mit der Cloud Spanner API erforderlich ist. Google.Cloud.Spanner.Data
. Mit dieser Änderung wird auch eine Referenz auf das Projekt CommandLineUtil
hinzugefügt, das Teil des GitHub-Repositorys „dotnet-doc-samples“ ist und eine nützliche „verbmap“ bietet. Erweiterung der Open-Source-Version CommandLineParser
; eine praktische Bibliothek für die Befehlszeileneingabe
in Konsolenanwendungen.
Mit der Datei Leaderboard.csproj
im Verzeichnis dotnet-docs-samples/applications/leaderboard/step4
können Sie sich ein Beispiel dafür ansehen, wie Ihre Datei Leaderboard.csproj
aussehen sollte, nachdem Sie den Code zum Aktivieren des Befehls create
hinzugefügt haben.
Jetzt können Sie das aktualisierte Beispiel ausführen. Geben Sie Folgendes ein, um die Standardantwort der aktualisierten Anwendung anzusehen:
dotnet run
Die Ausgabe sollte etwa so aussehen:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): No verb selected. create Create a sample Cloud Spanner database along with sample 'Players' and 'Scores' tables in your project. help Display more information on a specific command. version Display version information.
Dieser Antwort können wir entnehmen, dass dies die Anwendung Leaderboard
ist, die mit einem der drei möglichen Befehle ausgeführt werden kann: create
, help
und version
.
Lassen Sie uns den Befehl create
ausprobieren, um eine Spanner-Datenbank und -Tabellen zu erstellen. Führen Sie den Befehl ohne Argumente aus, um die erwarteten Argumente des Befehls anzuzeigen.
dotnet run create
Sie sollten eine Antwort wie die folgende sehen:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): A required value not bound to option name is missing. --help Display this help screen. --version Display version information. value pos. 0 Required. The project ID of the project to use when creating Cloud Spanner resources. value pos. 1 Required. The ID of the instance where the sample database will be created. value pos. 2 Required. The ID of the sample database to create.
Hier sehen Sie, dass die erwarteten Argumente des Befehls create
die Projekt-ID, die Instanz-ID und die Datenbank-ID sind.
Führen Sie nun den folgenden Befehl aus. Ersetzen Sie PROJECT_ID
durch die Projekt-ID, die Sie zu Beginn dieses Codelabs erstellt haben.
dotnet run create PROJECT_ID cloudspanner-leaderboard leaderboard
Nach einigen Sekunden sollten Sie eine Antwort wie die folgende sehen:
Waiting for operation to complete... Operation status: RanToCompletion Created sample database leaderboard on instance cloudspanner-leaderboard
Im Bereich „Cloud Spanner“ der Cloud Console sollten Sie im linken Menü Ihre neue Datenbank und Ihre Tabellen sehen.
Im nächsten Schritt aktualisieren wir unsere Anwendung, um einige Daten in Ihre neue Datenbank zu laden.
5. Daten laden
Wir haben jetzt eine Datenbank mit dem Namen leaderboard
, die zwei Tabellen enthält. Players
und Scores
. Verwenden wir nun die C#-Clientbibliothek, um unsere Tabelle Players
mit Spielern und unsere Tabelle Scores
mit Zufallsscores für jeden Spieler zu füllen.
Öffnen Sie den Cloud Shell-Editor, indem Sie auf das unten hervorgehobene Symbol klicken:
Bearbeiten Sie als Nächstes die Datei Program.cs
im Cloud Shell-Editor, um einen insert
-Befehl hinzuzufügen, mit dem 100 Spieler in die Tabelle Players
eingefügt werden können. Sie können damit auch 4 Zufallspunktzahlen für jeden Spieler in der Tabelle Players
in die Tabelle Scores
einfügen.
Fügen Sie zuerst einen neuen insert
-Befehlsblock in die Verbmap ein am Anfang des Programms unter dem vorhandenen create
-Befehlsblock:
[Verb("insert", HelpText = "Insert sample 'players' records or 'scores' records "
+ "into the database.")]
class InsertOptions
{
[Value(0, HelpText = "The project ID of the project to use "
+ "when managing Cloud Spanner resources.", Required = true)]
public string projectId { get; set; }
[Value(1, HelpText = "The ID of the instance where the sample database resides.",
Required = true)]
public string instanceId { get; set; }
[Value(2, HelpText = "The ID of the database where the sample database resides.",
Required = true)]
public string databaseId { get; set; }
[Value(3, HelpText = "The type of insert to perform, 'players' or 'scores'.",
Required = true)]
public string insertType { get; set; }
}
Fügen Sie als Nächstes unter der vorhandenen Methode CreateAsync
die folgenden Methoden Insert
, InsertPlayersAsync
und InsertScoresAsync
hinzu:
public static object Insert(string projectId,
string instanceId, string databaseId, string insertType)
{
if (insertType.ToLower() == "players")
{
var responseTask =
InsertPlayersAsync(projectId, instanceId, databaseId);
Console.WriteLine("Waiting for insert players operation to complete...");
responseTask.Wait();
Console.WriteLine($"Operation status: {responseTask.Status}");
}
else if (insertType.ToLower() == "scores")
{
var responseTask =
InsertScoresAsync(projectId, instanceId, databaseId);
Console.WriteLine("Waiting for insert scores operation to complete...");
responseTask.Wait();
Console.WriteLine($"Operation status: {responseTask.Status}");
}
else
{
Console.WriteLine("Invalid value for 'type of insert'. "
+ "Specify 'players' or 'scores'.");
return ExitCode.InvalidParameter;
}
Console.WriteLine($"Inserted {insertType} into sample database "
+ $"{databaseId} on instance {instanceId}");
return ExitCode.Success;
}
public static async Task InsertPlayersAsync(string projectId,
string instanceId, string databaseId)
{
string connectionString =
$"Data Source=projects/{projectId}/instances/{instanceId}"
+ $"/databases/{databaseId}";
long numberOfPlayers = 0;
using (var connection = new SpannerConnection(connectionString))
{
await connection.OpenAsync();
await connection.RunWithRetriableTransactionAsync(async (transaction) =>
{
// Execute a SQL statement to get current number of records
// in the Players table to use as an incrementing value
// for each PlayerName to be inserted.
var cmd = connection.CreateSelectCommand(
@"SELECT Count(PlayerId) as PlayerCount FROM Players");
numberOfPlayers = await cmd.ExecuteScalarAsync<long>();
// Insert 100 player records into the Players table.
SpannerBatchCommand cmdBatch = connection.CreateBatchDmlCommand();
for (int i = 0; i < 100; i++)
{
numberOfPlayers++;
SpannerCommand cmdInsert = connection.CreateDmlCommand(
"INSERT INTO Players "
+ "(PlayerId, PlayerName) "
+ "VALUES (@PlayerId, @PlayerName)",
new SpannerParameterCollection {
{"PlayerId", SpannerDbType.Int64},
{"PlayerName", SpannerDbType.String}});
cmdInsert.Parameters["PlayerId"].Value =
Math.Abs(Guid.NewGuid().GetHashCode());
cmdInsert.Parameters["PlayerName"].Value =
$"Player {numberOfPlayers}";
cmdBatch.Add(cmdInsert);
}
await cmdBatch.ExecuteNonQueryAsync();
});
}
Console.WriteLine("Done inserting player records...");
}
public static async Task InsertScoresAsync(
string projectId, string instanceId, string databaseId)
{
string connectionString =
$"Data Source=projects/{projectId}/instances/{instanceId}"
+ $"/databases/{databaseId}";
// Insert 4 score records into the Scores table for each player
// in the Players table.
using (var connection = new SpannerConnection(connectionString))
{
await connection.OpenAsync();
await connection.RunWithRetriableTransactionAsync(async (transaction) =>
{
Random r = new Random();
bool playerRecordsFound = false;
SpannerBatchCommand cmdBatch =
connection.CreateBatchDmlCommand();
var cmdLookup =
connection.CreateSelectCommand("SELECT * FROM Players");
using (var reader = await cmdLookup.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
playerRecordsFound = true;
for (int i = 0; i < 4; i++)
{
DateTime randomTimestamp = DateTime.Now
.AddYears(r.Next(-2, 1))
.AddMonths(r.Next(-12, 1))
.AddDays(r.Next(-28, 0))
.AddHours(r.Next(-24, 0))
.AddSeconds(r.Next(-60, 0))
.AddMilliseconds(r.Next(-100000, 0));
SpannerCommand cmdInsert =
connection.CreateDmlCommand(
"INSERT INTO Scores "
+ "(PlayerId, Score, Timestamp) "
+ "VALUES (@PlayerId, @Score, @Timestamp)",
new SpannerParameterCollection {
{"PlayerId", SpannerDbType.Int64},
{"Score", SpannerDbType.Int64},
{"Timestamp",
SpannerDbType.Timestamp}});
cmdInsert.Parameters["PlayerId"].Value =
reader.GetFieldValue<int>("PlayerId");
cmdInsert.Parameters["Score"].Value =
r.Next(1000, 1000001);
cmdInsert.Parameters["Timestamp"].Value =
randomTimestamp.ToString("o");
cmdBatch.Add(cmdInsert);
}
}
if (!playerRecordsFound)
{
Console.WriteLine("Parameter 'scores' is invalid "
+ "since no player records currently exist. First "
+ "insert players then insert scores.");
Environment.Exit((int)ExitCode.InvalidParameter);
}
else
{
await cmdBatch.ExecuteNonQueryAsync();
Console.WriteLine(
"Done inserting score records..."
);
}
}
});
}
}
Damit der insert
-Befehl funktioniert, fügen Sie der Hauptseite Ihres Programms den folgenden Code hinzu: :
.Add((InsertOptions opts) => Insert(
opts.projectId, opts.instanceId, opts.databaseId, opts.insertType))
Mit der Datei Program.cs
im Verzeichnis dotnet-docs-samples/applications/leaderboard/step5
können Sie sich ein Beispiel dafür ansehen, wie Ihre Datei Program.cs
aussehen sollte, nachdem Sie den Code zum Aktivieren des Befehls insert
hinzugefügt haben.
Führen Sie nun das Programm aus, um zu prüfen, ob der neue insert
-Befehl in der Liste der möglichen Befehle des Programms enthalten ist. Führen Sie dazu diesen Befehl aus:
dotnet run
Der Befehl insert
sollte jetzt in der Standardausgabe des Programms enthalten sein:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): No verb selected. create Create a sample Cloud Spanner database along with sample 'Players' and 'Scores' tables in your project. insert Insert sample 'players' records or 'scores' records into the database. help Display more information on a specific command. version Display version information.
Führen Sie nun den Befehl insert
aus, um die Eingabeargumente aufzurufen. Geben Sie den folgenden Befehl ein.
dotnet run insert
Daraufhin sollte die folgende Antwort zurückgegeben werden:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): A required value not bound to option name is missing. --help Display this help screen. --version Display version information. value pos. 0 Required. The project ID of the project to use when managing Cloud Spanner resources. value pos. 1 Required. The ID of the instance where the sample database resides. value pos. 2 Required. The ID of the database where the sample database resides. value pos. 3 Required. The type of insert to perform, 'players' or 'scores'.
Sie können der Antwort entnehmen, dass neben der Projekt-ID, Instanz-ID und Datenbank-ID noch das Argument value pos. 3
erwartet wird, nämlich den „Typ der Einfügung“. die Sie ausführen können. Dieses Argument kann den Wert „players“ haben. oder "Punktzahlen".
Jetzt führen wir den Befehl insert
mit denselben Argumentwerten aus, die wir beim Aufrufen des Befehls create
verwendet haben, und fügen „players“ hinzu. als zusätzlichen „Insert“-Typ . Ersetzen Sie PROJECT_ID
durch die Projekt-ID, die Sie zu Beginn dieses Codelabs erstellt haben.
dotnet run insert PROJECT_ID cloudspanner-leaderboard leaderboard players
Nach einigen Sekunden sollten Sie eine Antwort wie die folgende sehen:
Waiting for insert players operation to complete... Done inserting player records... Operation status: RanToCompletion Inserted players into sample database leaderboard on instance cloudspanner-leaderboard
Verwenden wir nun die C#-Clientbibliothek, um unsere Tabelle Scores
mit vier Zufallswerten und Zeitstempeln für jeden Spieler in der Tabelle Players
zu füllen.
Die Spalte Timestamp
der Tabelle „Scores
“ wurde als „Commit-Zeitstempel“ definiert Spalte über die folgende SQL-Anweisung, die ausgeführt wurde, als wir zuvor den Befehl create
ausgeführt haben:
CREATE TABLE Scores(
PlayerId INT64 NOT NULL,
Score INT64 NOT NULL,
Timestamp TIMESTAMP NOT NULL OPTIONS(allow_commit_timestamp=true)
) PRIMARY KEY(PlayerId, Timestamp),
INTERLEAVE IN PARENT Players ON DELETE NO ACTION
Beachten Sie das Attribut OPTIONS(allow_commit_timestamp=true)
. Dadurch wird Timestamp
zu einem „Commit-Zeitstempel“ und kann automatisch mit dem genauen Transaktionszeitstempel für INSERT- und UPDATE-Vorgänge in einer bestimmten Tabellenzeile gefüllt werden.
Sie können auch Ihre eigenen Zeitstempelwerte in einen Commit-Zeitstempel einfügen solange Sie einen Zeitstempel mit einem Wert in der Vergangenheit einfügen. In diesem Codelab machen wir das.
Führen wir nun den Befehl insert
mit denselben Argumentwerten aus, die wir beim Aufrufen des create
-Befehls verwendet haben, wobei wir „scores“ hinzufügen. als zusätzlichen „Insert“-Typ . Ersetzen Sie PROJECT_ID
durch die Projekt-ID, die Sie zu Beginn dieses Codelabs erstellt haben.
dotnet run insert PROJECT_ID cloudspanner-leaderboard leaderboard scores
Nach einigen Sekunden sollten Sie eine Antwort wie die folgende sehen:
Waiting for insert players operation to complete... Done inserting player records... Operation status: RanToCompletion Inserted players into sample database leaderboard on instance cloudspanner-leaderboard
insert
mit dem „type of insert“ ausführen , das als scores
angegeben ist, ruft die Methode InsertScoresAsync
auf, die die folgenden Code-Snippets verwendet, um einen zufällig generierten Zeitstempel mit einem Datum und einer Uhrzeit einzufügen, die in der Vergangenheit liegen:
DateTime randomTimestamp = DateTime.Now
.AddYears(r.Next(-2, 1))
.AddMonths(r.Next(-12, 1))
.AddDays(r.Next(-28, 0))
.AddHours(r.Next(-24, 0))
.AddSeconds(r.Next(-60, 0))
.AddMilliseconds(r.Next(-100000, 0));
...
cmdInsert.Parameters["Timestamp"].Value = randomTimestamp.ToString("o");
Um die Spalte Timestamp
automatisch mit dem Zeitstempel zu füllen, der genau dem Zeitpunkt entspricht, an dem das Transaktion stattfindet, können Sie stattdessen die C#-Konstante SpannerParameter.CommitTimestamp
wie im folgenden Code-Snippet einfügen:
cmd.Parameters["Timestamp"].Value = SpannerParameter.CommitTimestamp;
Nachdem die Daten geladen wurden, überprüfen wir die Werte, die wir gerade in unsere neuen Tabellen geschrieben haben. Wählen Sie zuerst die Datenbank leaderboard
und dann die Tabelle Players
aus. Klicken Sie auf den Tab Data
. Sie sollten sehen, dass sich in den Spalten PlayerId
und PlayerName
der Tabelle Daten befinden.
Prüfen Sie als Nächstes, ob die Tabelle „Scores“ auch Daten enthält. Klicken Sie dazu auf die Tabelle Scores
und wählen Sie den Tab Data
aus. Die Spalten PlayerId
, Timestamp
und Score
der Tabelle sollten Daten enthalten.
Gut gemacht! Wir möchten unser Programm aktualisieren und einige Abfragen ausführen, mit denen wir eine Gaming-Bestenliste erstellen können.
6. Abfragen zu Bestenlisten ausführen
Nachdem wir unsere Datenbank eingerichtet und Informationen in unsere Tabellen geladen haben, erstellen wir nun mit diesen Daten eine Bestenliste. Dazu müssen wir die folgenden vier Fragen beantworten:
- Welche Spieler sind die "Top Ten"? aller Zeiten?
- Welche Spieler sind die "Top Ten"? des Jahres?
- Welche Spieler sind die "Top Ten"? des Monats?
- Welche Spieler sind die "Top Ten"? der Woche?
Lassen Sie uns unser Programm aktualisieren, um die SQL-Abfragen auszuführen, die diese Fragen beantworten.
Wir fügen einen query
-Befehl hinzu, der eine Möglichkeit bietet, die Abfragen auszuführen, um die Fragen zu beantworten, die die für unsere Bestenliste erforderlichen Informationen liefern.
Bearbeiten Sie die Datei Program.cs
im Cloud Shell-Editor, um dem Programm einen query
-Befehl hinzuzufügen.
Fügen Sie zuerst einen neuen query
-Befehlsblock in die Verbmap ein am Anfang des Programms unter dem vorhandenen insert
-Befehlsblock:
[Verb("query", HelpText = "Query players with 'Top Ten' scores within a specific timespan "
+ "from sample Cloud Spanner database table.")]
class QueryOptions
{
[Value(0, HelpText = "The project ID of the project to use "
+ "when managing Cloud Spanner resources.", Required = true)]
public string projectId { get; set; }
[Value(1, HelpText = "The ID of the instance where the sample data resides.",
Required = true)]
public string instanceId { get; set; }
[Value(2, HelpText = "The ID of the database where the sample data resides.",
Required = true)]
public string databaseId { get; set; }
[Value(3, Default = 0, HelpText = "The timespan in hours that will be used to filter the "
+ "results based on a record's timestamp. The default will return the "
+ "'Top Ten' scores of all time.")]
public int timespan { get; set; }
}
Fügen Sie als Nächstes unter der vorhandenen Methode InsertScoresAsync
die folgenden Methoden Query
und QueryAsync
hinzu:
public static object Query(string projectId,
string instanceId, string databaseId, int timespan)
{
var response = QueryAsync(
projectId, instanceId, databaseId, timespan);
response.Wait();
return ExitCode.Success;
}
public static async Task QueryAsync(
string projectId, string instanceId, string databaseId, int timespan)
{
string connectionString =
$"Data Source=projects/{projectId}/instances/"
+ $"{instanceId}/databases/{databaseId}";
// Create connection to Cloud Spanner.
using (var connection = new SpannerConnection(connectionString))
{
string sqlCommand;
if (timespan == 0)
{
// No timespan specified. Query Top Ten scores of all time.
sqlCommand =
@"SELECT p.PlayerId, p.PlayerName, s.Score, s.Timestamp
FROM Players p
JOIN Scores s ON p.PlayerId = s.PlayerId
ORDER BY s.Score DESC LIMIT 10";
}
else
{
// Query Top Ten scores filtered by the timepan specified.
sqlCommand =
$@"SELECT p.PlayerId, p.PlayerName, s.Score, s.Timestamp
FROM Players p
JOIN Scores s ON p.PlayerId = s.PlayerId
WHERE s.Timestamp >
TIMESTAMP_SUB(CURRENT_TIMESTAMP(),
INTERVAL {timespan.ToString()} HOUR)
ORDER BY s.Score DESC LIMIT 10";
}
var cmd = connection.CreateSelectCommand(sqlCommand);
using (var reader = await cmd.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
Console.WriteLine("PlayerId : "
+ reader.GetFieldValue<string>("PlayerId")
+ " PlayerName : "
+ reader.GetFieldValue<string>("PlayerName")
+ " Score : "
+ string.Format("{0:n0}",
Int64.Parse(reader.GetFieldValue<string>("Score")))
+ " Timestamp : "
+ reader.GetFieldValue<string>("Timestamp").Substring(0, 10));
}
}
}
}
Damit der query
-Befehl funktioniert, fügen Sie der Hauptseite Ihres Programms den folgenden Code hinzu: :
.Add((QueryOptions opts) => Query(
opts.projectId, opts.instanceId, opts.databaseId, opts.timespan))
Mit der Datei Program.cs
im Verzeichnis dotnet-docs-samples/applications/leaderboard/step6
können Sie sich ein Beispiel dafür ansehen, wie Ihre Datei Program.cs
aussehen sollte, nachdem Sie den Code zum Aktivieren des Befehls query
hinzugefügt haben.
Führen Sie nun das Programm aus, um zu prüfen, ob der neue query
-Befehl in der Liste der möglichen Befehle des Programms enthalten ist. Führen Sie dazu diesen Befehl aus:
dotnet run
Der Befehl query
sollte jetzt in der Standardausgabe des Programms als neue Befehlsoption enthalten sein:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): No verb selected. create Create a sample Cloud Spanner database along with sample 'Players' and 'Scores' tables in your project. insert Insert sample 'players' records or 'scores' records into the database. query Query players with 'Top Ten' scores within a specific timespan from sample Cloud Spanner database table. help Display more information on a specific command. version Display version information.
Führen Sie nun den Befehl query
aus, um die Eingabeargumente aufzurufen. Geben Sie den folgenden Befehl ein:
dotnet run query
Dadurch wird die folgende Antwort zurückgegeben:
Leaderboard 1.0.0 Copyright (C) 2018 Leaderboard ERROR(S): A required value not bound to option name is missing. --help Display this help screen. --version Display version information. value pos. 0 Required. The project ID of the project to use when managing Cloud Spanner resources. value pos. 1 Required. The ID of the instance where the sample data resides. value pos. 2 Required. The ID of the database where the sample data resides. value pos. 3 (Default: 0) The timespan in hours that will be used to filter the results based on a record's timestamp. The default will return the 'Top Ten' scores of all time.
Sie können der Antwort entnehmen, dass neben der Projekt-ID, Instanz-ID und Datenbank-ID auch das Argument value pos. 3
erwartet wird, mit dem wir eine Zeitspanne in Stunden angeben können, die zum Filtern von Datensätzen basierend auf ihrem Wert in der Spalte Timestamp
der Tabelle Scores
verwendet werden soll. Dieses Argument hat den Standardwert 0, was bedeutet, dass keine Datensätze nach Zeitstempeln gefiltert werden. Wir können also den Befehl query
ohne „timespan“ verwenden. um eine Liste der Top Ten zu erhalten, aller Zeiten.
Lassen Sie uns den Befehl query
ohne Angabe einer Zeitspanne ausführen. Verwenden Sie dabei dieselben Argumentwerte, die wir bei der Ausführung des Befehls create
verwendet haben. Ersetzen Sie PROJECT_ID
durch die Projekt-ID, die Sie zu Beginn dieses Codelabs erstellt haben.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard
Sie sollten nun eine Antwort sehen, die die Top Ten enthält. wie die folgenden:
PlayerId : 1843159180 PlayerName : Player 87 Score : 998,955 Timestamp : 2016-03-23
PlayerId : 61891198 PlayerName : Player 19 Score : 998,720 Timestamp : 2016-03-26
PlayerId : 340906298 PlayerName : Player 48 Score : 993,302 Timestamp : 2015-08-27
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 857460496 PlayerName : Player 68 Score : 988,010 Timestamp : 2015-05-25
PlayerId : 1826646419 PlayerName : Player 91 Score : 984,022 Timestamp : 2016-11-26
PlayerId : 1002199735 PlayerName : Player 35 Score : 982,933 Timestamp : 2015-09-26
PlayerId : 2002563755 PlayerName : Player 23 Score : 979,041 Timestamp : 2016-10-25
PlayerId : 1377548191 PlayerName : Player 2 Score : 978,632 Timestamp : 2016-05-02
PlayerId : 1358098565 PlayerName : Player 65 Score : 973,257 Timestamp : 2016-10-30
Führen wir nun den Befehl query
mit den erforderlichen Argumenten aus, um die Top Ten abzufragen. Spieler des Jahres durch Angabe einer „Zeitspanne“ entspricht der Anzahl der Stunden in einem Jahr, also 8.760. Ersetzen Sie PROJECT_ID
durch die Projekt-ID, die Sie zu Beginn dieses Codelabs erstellt haben.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard 8760
Sie sollten nun eine Antwort sehen, die die Top Ten enthält. Spieler des Jahres:
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 228469898 PlayerName : Player 82 Score : 967,177 Timestamp : 2018-01-26
PlayerId : 1131343000 PlayerName : Player 26 Score : 944,725 Timestamp : 2017-05-26
PlayerId : 396780730 PlayerName : Player 41 Score : 929,455 Timestamp : 2017-09-26
PlayerId : 61891198 PlayerName : Player 19 Score : 921,251 Timestamp : 2018-05-01
PlayerId : 634269851 PlayerName : Player 54 Score : 909,379 Timestamp : 2017-07-24
PlayerId : 821111159 PlayerName : Player 55 Score : 908,402 Timestamp : 2017-05-25
PlayerId : 228469898 PlayerName : Player 82 Score : 889,040 Timestamp : 2017-12-26
PlayerId : 1408782275 PlayerName : Player 27 Score : 874,124 Timestamp : 2017-09-24
PlayerId : 1002199735 PlayerName : Player 35 Score : 864,758 Timestamp : 2018-04-24
Führen wir nun den Befehl query
aus, um die Top Ten abzufragen. Spieler des Monats durch Angabe einer Zeitspanne der Anzahl der Stunden pro Monat,
also 730. Ersetzen Sie PROJECT_ID
durch die Projekt-ID, die Sie zu Beginn dieses Codelabs erstellt haben.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard 730
Sie sollten nun eine Antwort sehen, die die Top Ten enthält. Spieler des Monats:
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 61891198 PlayerName : Player 19 Score : 921,251 Timestamp : 2018-05-01
PlayerId : 1002199735 PlayerName : Player 35 Score : 864,758 Timestamp : 2018-04-24
PlayerId : 1228490432 PlayerName : Player 11 Score : 682,033 Timestamp : 2018-04-26
PlayerId : 648239230 PlayerName : Player 92 Score : 653,895 Timestamp : 2018-05-02
PlayerId : 70762849 PlayerName : Player 77 Score : 598,074 Timestamp : 2018-04-22
PlayerId : 1671215342 PlayerName : Player 62 Score : 506,770 Timestamp : 2018-04-28
PlayerId : 1208850523 PlayerName : Player 21 Score : 216,008 Timestamp : 2018-04-30
PlayerId : 1587692674 PlayerName : Player 63 Score : 188,157 Timestamp : 2018-04-25
PlayerId : 992391797 PlayerName : Player 37 Score : 167,175 Timestamp : 2018-04-30
Führen wir nun den Befehl query
aus, um die Top Ten abzufragen. der Woche durch Angabe einer
„Zeitraum“-Zeitspanne der Anzahl der Stunden pro Woche (168). Ersetzen Sie PROJECT_ID
durch die Projekt-ID, die Sie zu Beginn dieses Codelabs erstellt haben.
dotnet run query PROJECT_ID cloudspanner-leaderboard leaderboard 168
Sie sollten nun eine Antwort sehen, die die Top Ten enthält. der Woche:
PlayerId : 541473117 PlayerName : Player 22 Score : 991,368 Timestamp : 2018-04-30
PlayerId : 61891198 PlayerName : Player 19 Score : 921,251 Timestamp : 2018-05-01
PlayerId : 228469898 PlayerName : Player 82 Score : 853,602 Timestamp : 2018-04-28
PlayerId : 1131343000 PlayerName : Player 26 Score : 695,318 Timestamp : 2018-04-30
PlayerId : 1228490432 PlayerName : Player 11 Score : 682,033 Timestamp : 2018-04-26
PlayerId : 1408782275 PlayerName : Player 27 Score : 671,827 Timestamp : 2018-04-27
PlayerId : 648239230 PlayerName : Player 92 Score : 653,895 Timestamp : 2018-05-02
PlayerId : 816861444 PlayerName : Player 83 Score : 622,277 Timestamp : 2018-04-27
PlayerId : 162043954 PlayerName : Player 75 Score : 572,634 Timestamp : 2018-05-02
PlayerId : 1671215342 PlayerName : Player 62 Score : 506,770 Timestamp : 2018-04-28
Super!
Wenn Sie jetzt Einträge hinzufügen, skaliert Spanner Ihre Datenbank auf eine beliebige Größe.
Unabhängig davon, wie stark Ihre Datenbank wächst, kann die Bestenliste Ihres Spiels mit Spanner und seiner Truetime-Technologie weiterhin präzise skaliert werden.
7. Bereinigen
Nach so viel Spaß beim Spielen mit Spanner müssen wir unseren Spielplatz aufräumen und dabei kostbare Ressourcen und Geld sparen. Dies ist ein einfacher Schritt. Rufen Sie einfach die Developer Console auf und löschen Sie die Instanz, die Sie im Codelab-Schritt "Setup a Cloud Spanner Instance" (Cloud Spanner-Instanz einrichten) erstellt haben.
8. Glückwunsch!
Behandelte Themen:
- Google Cloud Spanner-Instanzen, -Datenbanken und -Tabellenschema für eine Bestenliste
- .NET Core-C#-Konsolenanwendung erstellen
- Spanner-Datenbank und -Tabellen mit der C#-Clientbibliothek erstellen
- Daten mithilfe der C#-Clientbibliothek in eine Spanner-Datenbank laden
- Abfrage der „Top Ten“ Ergebnisse aus Ihren Daten mithilfe von Spanner-Commit-Zeitstempeln und der C#-Clientbibliothek
Vorgehensweise:
- Spanner CAP-Whitepaper lesen
- Weitere Informationen zum Schemadesign und zu Best Practices für Abfragen
- Weitere Informationen zu Commit-Zeitstempeln in Cloud Spanner
Feedback geben
- Bitte nehmen Sie sich einen Moment Zeit, um an unserer kurzen Umfrage teilzunehmen.