Commit-Statistiken für eine Transaktion abrufen

Damit Sie Transaktionsprobleme besser verstehen, optimieren und diagnostizieren können, bietet Spanner Zugriff auf Statistiken zu Transaktions-Commits. Derzeit können Sie die Gesamtzahl der Mutationen für eine Transaktion abrufen.

Wann Commit-Statistiken nützlich sind

Die Anzahl der Mutationen für eine Transaktion zu kennen, kann in den folgenden Szenarien hilfreich sein.

Für Hin- und Rückflug optimieren

Zur Verbesserung der Leistung Ihrer Anwendung können Sie die Anzahl der Umläufe zur Datenbank reduzieren, indem Sie bei jeder Transaktion so viele Aufgaben wie möglich erledigen. In diesem Szenario möchten Sie die Anzahl der Mutationen pro Transaktion maximieren und gleichzeitig innerhalb der Systemgrenzen bleiben.

Um zu ermitteln, wie viele Zeilen Sie pro Transaktion mit Commit unter dem Limit festschreiben können, führen Sie zuerst einen Commit für eine Zeile in einer Transaktion durch. Dies gibt Ihnen eine Basislinie für die Mutationszahl pro Zeile. Teilen Sie dann das Systemlimit durch Ihre Referenz, um die Anzahl der Zeilen pro Transaktion zu erhalten. Weitere Informationen zum Zählen von Mutationen finden Sie in diesem Hinweis.

Beachten Sie, dass die Optimierung für Umläufe nicht immer vorteilhaft ist, insbesondere wenn dies zu mehr Sperrkonflikten führt. Sie können Sperrkonflikte in Ihrer Datenbank mithilfe von Sperrstatistiken lösen.

Transaktionen im Blick behalten, um das Überschreiten der Systemlimits zu vermeiden

Wenn die Anwendungsnutzung zunimmt, ist es möglich, dass auch die Anzahl der Mutationen in Ihrer Transaktion zunimmt. Um zu verhindern, dass das Systemlimit erreicht wird und Ihre Transaktion schließlich fehlschlägt, können Sie die Commit-Statistik der Mutationszahl im Laufe der Zeit proaktiv überwachen. Wenn dieser Wert für dieselbe Transaktion steigt, kann es an der Zeit sein, die Transaktion wie im vorherigen Abschnitt beschrieben neu zu optimieren.

Commit-Statistiken aufrufen

Commit-Statistiken werden standardmäßig nicht zurückgegeben. Stattdessen müssen Sie das Flag return_commit_stats bei jeder CommitRequest auf "true" setzen. Wenn Ihr Commit-Versuch die maximal zulässige Anzahl von Mutationen für eine Transaktion überschreitet, schlägt der Commit fehl und der Fehler INVALID_ARGUMENT wird zurückgegeben.

Im Folgenden finden Sie ein Beispiel für die Rückgabe von Commit-Statistiken mithilfe der Spanner-Clientbibliotheken.

Commit-Statistiken abrufen

Im folgenden Beispiel wird gezeigt, wie Sie Commit-Statistiken mithilfe der Spanner-Clientbibliotheken abrufen.

C++

Der folgende Code ruft set_return_stats() auf CommitOptions auf und gibt eine Mutationszahl von 6 zurück, da wir in jeder Zeile zwei Zeilen und drei Spalten einfügen oder aktualisieren.

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

  auto commit = client.Commit(
      spanner::Mutations{
          spanner::UpdateMutationBuilder(
              "Albums", {"SingerId", "AlbumId", "MarketingBudget"})
              .EmplaceRow(1, 1, 200000)
              .EmplaceRow(2, 2, 400000)
              .Build()},
      google::cloud::Options{}.set<spanner::CommitReturnStatsOption>(true));

  if (!commit) throw std::move(commit).status();
  if (commit->commit_stats) {
    std::cout << "Updated data with " << commit->commit_stats->mutation_count
              << " mutations.\n";
  }
  std::cout << "Update was successful [spanner_get_commit_stats]\n";
}

C#

In C# werden Commit-Statistiken nicht direkt über die API zurückgegeben. Sie werden stattdessen vom Standard-Logger auf die Logebene Informationen protokolliert.

Mit dem folgenden Code wird das Commit-Statistik-Logging für alle Transaktionen aktiviert. Setzen Sie dazu das Attribut LogCommitStats in SpannerConnectionStringBuilder auf "true". Der Code implementiert auch einen Beispiel-Logger, der einen Verweis auf die zuletzt erfasste Commit-Antwort speichert. Der MutationCount wird dann aus dieser Antwort abgerufen und angezeigt.


using Google.Cloud.Spanner.Data;
using Google.Cloud.Spanner.V1;
using Google.Cloud.Spanner.V1.Internal.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

public class LogCommitStatsAsyncSample
{
    public async Task<long> LogCommitStatsAsync(string projectId, string instanceId, string databaseId)
    {
        // Commit statistics are logged at level Info by the default logger.
        // This sample uses a custom logger to access the commit statistics.
        // See https://googleapis.github.io/google-cloud-dotnet/docs/Google.Cloud.Spanner.Data/logging.html
        // for more information on how to use loggers.
        var logger = new CommitStatsSampleLogger();
        var options = new SessionPoolOptions();
        var poolManager = SessionPoolManager.Create(options, logger);
        var connectionStringBuilder = new SpannerConnectionStringBuilder
        {
            ConnectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}",
            // Set LogCommitStats to true to enable logging commit statistics for all transactions on the connection.
            // LogCommitStats can also be enabled/disabled for individual Spanner transactions.
            LogCommitStats = true,
            SessionPoolManager = poolManager,
        };

        using var connection = new SpannerConnection(connectionStringBuilder);
        await connection.OpenAsync();

        using var cmd = connection.CreateDmlCommand("INSERT Singers (SingerId, FirstName, LastName) VALUES (110, 'Virginia', 'Watson')");
        var rowCount = await cmd.ExecuteNonQueryAsync();
        var mutationCount = logger._lastCommitResponse.CommitStats.MutationCount;

        Console.WriteLine($"{rowCount} row(s) inserted...");
        Console.WriteLine($"{mutationCount} mutation(s) in transaction...");

        return mutationCount;
    }

    /// <summary>
    /// Sample logger that keeps a reference to the last seen commit response.
    /// Use the default logger if you only want to log the commit stats.
    /// </summary>
    public class CommitStatsSampleLogger : Logger
    {
        internal CommitResponse _lastCommitResponse;

        /// <summary>
        /// This method is called when a transaction that requested commit stats is committed.
        /// </summary>
        public override void LogCommitStats(CommitRequest request, CommitResponse response)
        {
            _lastCommitResponse = response;
            base.LogCommitStats(request, response);
        }

        protected override void LogImpl(LogLevel level, string message, Exception exception) =>
            WriteLine(exception == null ? $"{level}: {message}" : $"{level}: {message}, Exception: {exception}");

        protected override void LogPerformanceEntries(IEnumerable<string> entries)
        {
            string separator = Environment.NewLine + "  ";
            WriteLine($"Performance:{separator}{string.Join(separator, entries)}");
        }

        private void WriteLine(string line) => Trace.TraceInformation(line);
    }
}

Einfach loslegen (Go)

Mit dem folgenden Code wird das Flag ReturnCommitStats festgelegt und die Mutationsanzahl ausgegeben, wenn die Transaktion erfolgreich übergeben wurde.


import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/spanner"
)

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

	resp, err := client.ReadWriteTransactionWithOptions(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
		stmt := spanner.Statement{
			SQL: `INSERT Singers (SingerId, FirstName, LastName)
					VALUES (110, 'Virginia', 'Watson')`,
		}
		rowCount, err := txn.Update(ctx, stmt)
		if err != nil {
			return err
		}
		fmt.Fprintf(w, "%d record(s) inserted.\n", rowCount)
		return nil
	}, spanner.TransactionOptions{CommitOptions: spanner.CommitOptions{ReturnCommitStats: true}})
	if err != nil {
		return fmt.Errorf("commitStats.ReadWriteTransactionWithOptions: %w", err)
	}
	fmt.Fprintf(w, "%d mutations in transaction\n", resp.CommitStats.MutationCount)
	return nil
}

Java


import com.google.cloud.spanner.CommitResponse;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.Options;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import java.util.Arrays;

public class GetCommitStatsSample {

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

    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
      final DatabaseClient databaseClient = spanner
          .getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
      getCommitStats(databaseClient);
    }
  }

  static void getCommitStats(DatabaseClient databaseClient) {
    final CommitResponse commitResponse = databaseClient.writeWithOptions(Arrays.asList(
        Mutation.newInsertOrUpdateBuilder("Albums")
            .set("SingerId")
            .to("1")
            .set("AlbumId")
            .to("1")
            .set("MarketingBudget")
            .to("200000")
            .build(),
        Mutation.newInsertOrUpdateBuilder("Albums")
            .set("SingerId")
            .to("2")
            .set("AlbumId")
            .to("2")
            .set("MarketingBudget")
            .to("400000")
            .build()
    ), Options.commitStats());

    System.out.println(
        "Updated data with " + commitResponse.getCommitStats().getMutationCount() + " mutations.");
  }
}

Node.js

Der folgende Code legt das Flag returnCommitStats fest und gibt eine Mutationszahl von 6 zurück, da wir in jeder Zeile zwei Zeilen und drei Spalten einfügen oder aktualisieren.

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

// Instantiate Spanner table objects.
const albumsTable = database.table('Albums');

// Updates rows in the Venues table.
try {
  const [response] = await albumsTable.upsert(
    [
      {SingerId: '1', AlbumId: '1', MarketingBudget: '200000'},
      {SingerId: '2', AlbumId: '2', MarketingBudget: '400000'},
    ],
    {returnCommitStats: true}
  );
  console.log(
    `Updated data with ${response.commitStats.mutationCount} mutations.`
  );
} catch (err) {
  console.error('ERROR:', err);
} finally {
  // Close the database when finished.
  database.close();
}

PHP

use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Transaction;

/**
 * Creates a database and tables for sample data.
 * Example:
 * ```
 * create_database($instanceId, $databaseId);
 * ```
 *
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function get_commit_stats(string $instanceId, string $databaseId): void
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $commitStats = $database->runTransaction(function (Transaction $t) {
        $t->updateBatch('Albums', [
            [
                'SingerId' => 1,
                'AlbumId' => 1,
                'MarketingBudget' => 200000,
            ],
            [
                'SingerId' => 2,
                'AlbumId' => 2,
                'MarketingBudget' => 400000,
            ]
        ]);
        $t->commit(['returnCommitStats' => true]);
        return $t->getCommitStats();
    });

    print('Updated data with ' . $commitStats['mutationCount'] . ' mutations.' . PHP_EOL);
}

Python

Anstatt Commit-Statistiken direkt über die API zurückzugeben, protokolliert die Python-Clientbibliothek sie mit stdout auf der Ebene Info.

Der folgende Code aktiviert das Commit-Statistik-Logging für alle Transaktionen durch Festlegen von database.log_commit_stats = True. Der Code implementiert auch einen Beispiel-Logger, der einen Verweis auf die zuletzt erfasste Commit-Antwort speichert. Der mutation_count wird dann aus dieser Antwort abgerufen und angezeigt.

def log_commit_stats(instance_id, database_id):
    """Inserts sample data using DML and displays the commit statistics."""

    # By default, commit statistics are logged via stdout at level Info.
    # This sample uses a custom logger to access the commit statistics.
    class CommitStatsSampleLogger(logging.Logger):
        def __init__(self):
            self.last_commit_stats = None
            super().__init__("commit_stats_sample")

        def info(self, msg, *args, **kwargs):
            if kwargs["extra"] and "commit_stats" in kwargs["extra"]:
                self.last_commit_stats = kwargs["extra"]["commit_stats"]
            super().info(msg)

    spanner_client = spanner.Client()
    instance = spanner_client.instance(instance_id)
    database = instance.database(database_id, logger=CommitStatsSampleLogger())
    database.log_commit_stats = True

    def insert_singers(transaction):
        row_ct = transaction.execute_update(
            "INSERT Singers (SingerId, FirstName, LastName) "
            " VALUES (110, 'Virginia', 'Watson')"
        )

        print("{} record(s) inserted.".format(row_ct))

    database.run_in_transaction(insert_singers)
    commit_stats = database.logger.last_commit_stats
    print("{} mutation(s) in transaction.".format(commit_stats.mutation_count))

Ruby

Der folgende Code legt das Flag return_commit_stats fest und gibt eine Mutationszahl von 6 zurück, da wir in jeder Zeile zwei Zeilen und drei Spalten einfügen oder aktualisieren.

# 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

records = [
  { SingerId: 1, AlbumId: 1, MarketingBudget: 200_000 },
  { SingerId: 2, AlbumId: 2, MarketingBudget: 400_000 }
]
commit_options = { return_commit_stats: true }
resp = client.upsert "Albums", records, commit_options: commit_options
puts "Updated data with #{resp.stats.mutation_count} mutations."

Nächste Schritte