Mengambil statistik commit untuk transaksi

Untuk membantu Anda lebih memahami, mengoptimalkan, dan mendiagnosis masalah transaksi, Spanner memberi Anda akses ke statistik commit transaksi. Saat ini, Anda dapat mengambil jumlah total mutasi untuk sebuah transaksi.

Kapan harus menggunakan statistik commit

Mengetahui jumlah mutasi untuk sebuah transaksi dapat berguna dalam skenario berikut.

Mengoptimalkan perjalanan pulang pergi

Untuk membantu meningkatkan performa aplikasi, Anda dapat mengurangi jumlah perjalanan pulang pergi ke database dengan melakukan pekerjaan sebanyak mungkin dalam setiap transaksi. Dalam skenario ini, Anda ingin memaksimalkan jumlah mutasi per transaksi, sambil tetap berada dalam batas sistem.

Untuk menentukan jumlah baris yang dapat Anda commit per transaksi tanpa melampaui batas, pertama-tama commit satu baris dalam transaksi. Ini memberi Anda dasar pengukuran jumlah mutasi per baris. Kemudian bagi batas sistem dengan garis dasar Anda untuk mendapatkan nomor baris per transaksi. Untuk informasi lebih lanjut tentang cara menghitung mutasi, lihat catatan ini.

Perhatikan bahwa pengoptimalan untuk perjalanan bolak-balik tidak selalu bermanfaat, terutama jika menghasilkan lebih banyak pertentangan kunci. Anda dapat memecahkan masalah konflik kunci di database menggunakan statistik kunci.

Pantau transaksi Anda agar tidak mencapai batas sistem

Seiring meningkatnya penggunaan aplikasi, ada kemungkinan jumlah mutasi dalam transaksi Anda juga akan meningkat. Untuk menghindari tercapainya batas sistem dan pada akhirnya transaksi Anda gagal, Anda dapat secara proaktif memantau statistik commit jumlah mutasi dari waktu ke waktu. Jika Anda mengamati peningkatan nilai ini untuk transaksi yang sama, mungkin sudah waktunya untuk mengoptimalkan ulang transaksi Anda seperti yang dijelaskan di bagian sebelumnya.

Cara mengakses statistik commit

Statistik commit tidak ditampilkan secara default. Sebagai gantinya, Anda perlu menetapkan tanda return_commit_stats ke benar (true) pada setiap CommitRequest. Jika upaya commit Anda melebihi jumlah mutasi maksimum yang diizinkan untuk suatu transaksi, commit akan gagal dan error INVALID_ARGUMENT akan ditampilkan.

Berikut adalah contoh cara menampilkan statistik commit menggunakan library klien Spanner.

Mengambil statistik commit

Contoh berikut menunjukkan cara mendapatkan statistik commit menggunakan library klien Spanner.

C++

Kode berikut memanggil set_return_stats() pada CommitOptions dan menampilkan jumlah mutasi 6 karena kita menyisipkan atau memperbarui 2 baris dan 3 kolom di setiap baris.

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#

Di C#, statistik commit tidak ditampilkan secara langsung melalui API. Sebaliknya, logger tersebut dicatat ke dalam log pada level log Informasi oleh logger default.

Kode berikut memungkinkan logging statistik commit untuk semua transaksi dengan menetapkan properti LogCommitStats di SpannerConnectionStringBuilder ke benar (true). Kode ini juga menerapkan logger contoh yang menyimpan referensi ke respons commit yang terakhir dilihat. MutationCount kemudian diambil dari respons ini dan ditampilkan.


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

Go

Kode berikut menetapkan flag ReturnCommitStats dan mencetak jumlah mutasi saat transaksi berhasil di-commit.


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

Kode berikut menetapkan flag returnCommitStats dan menampilkan jumlah mutasi 6, karena kita menyisipkan atau memperbarui 2 baris dan 3 kolom di setiap baris.

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

Alih-alih menampilkan statistik commit secara langsung melalui API, library klien Python akan mencatatnya menggunakan stdout pada level Info.

Kode berikut memungkinkan logging statistik commit untuk semua transaksi dengan menetapkan database.log_commit_stats = True. Kode ini juga menerapkan contoh logger yang menyimpan referensi ke respons commit yang terakhir dilihat. mutation_count kemudian diambil dari respons ini dan ditampilkan.

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

Kode berikut menetapkan flag return_commit_stats dan menampilkan jumlah mutasi 6, karena kita menyisipkan atau memperbarui 2 baris dan 3 kolom di setiap baris.

# 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."

Langkah selanjutnya