אחזור נתונים סטטיסטיים של ביצוע פעולות בעסקה

כדי לעזור לכם להבין, לשפר ולאבחן בעיות בעסקאות, Spanner מאפשר לכם לגשת לנתונים סטטיסטיים של אישור עסקאות. בשלב הזה, אפשר לאחזר את המספר הכולל של שינויים בעסקה.

מתי כדאי להשתמש בנתוני סטטוס של שליחת שינויים

הידיעה כמה מוטציות יש לטרנזקציה יכולה להיות שימושית בתרחישים הבאים.

אופטימיזציה של נסיעות הלוך ושוב

כדי לשפר את הביצועים של האפליקציה, אפשר לצמצם את מספר הנסיעות הלוך ושוב למסד הנתונים על ידי ביצוע כמה שיותר פעולות בכל טרנזקציה. במקרה כזה, כדאי להגדיל את מספר המוטציות לכל טרנזקציה, תוך שמירה על מגבלות המערכת.

כדי לקבוע כמה שורות אפשר לבצע בכל טרנזקציה בלי לחרוג מהמגבלה, קודם צריך לבצע שורה אחת בטרנזקציה. כך מקבלים קו בסיס של מספר המוטציות לכל שורה. לאחר מכן מחלקים את המגבלה של המערכת בערך הבסיסי כדי לקבל את מספר השורות לכל עסקה. מידע נוסף על אופן הספירה של מוטציות זמין בהערה הזו.

חשוב לזכור: אופטימיזציה של נסיעות הלוך ושוב לא תמיד מועילה, במיוחד אם היא מובילה ליותר התנגשויות של נעילות. אפשר לפתור בעיות שקשורות לנעילות במסד הנתונים באמצעות נתונים סטטיסטיים על נעילות.

מעקב אחרי העסקאות כדי לא לחרוג ממגבלות המערכת

ככל שהשימוש באפליקציה גדל, יכול להיות שמספר השינויים בעסקה גדל גם הוא. כדי להימנע מהגעה למגבלת המערכת ומהמצב שבו העסקה תיכשל בסופו של דבר, אפשר לעקוב באופן יזום לאורך זמן אחרי נתון הסטטיסטיקה של מספר השינויים שבוצעו. אם אתם רואים שהערך הזה עולה עבור אותה עסקה, יכול להיות שהגיע הזמן לבצע אופטימיזציה מחדש של העסקה, כמו שמתואר בקטע הקודם.

איך ניגשים לסטטיסטיקות של פעולות Commit

כברירת מחדל, לא מוחזרת סטטיסטיקה של ביצוע פעולות Commit. במקום זאת, צריך להגדיר את הדגל return_commit_stats לערך true בכל CommitRequest. אם ניסיון השליחה חורג ממספר המוטציות המקסימלי המותר לעסקה, השליחה נכשלת ומוחזרת שגיאה מסוג INVALID_ARGUMENT.

הנה דוגמה להחזרת נתוני סטטיסטיקה של ביצוע פעולות באמצעות ספריות הלקוח של Spanner.

אחזור נתוני קומיטים

בדוגמה הבאה מוצג איך לקבל נתונים סטטיסטיים של ביצוע פעולות Commit באמצעות ספריות הלקוח של Spanner.

C++‎

הקוד הבא קורא ל-set_return_stats() ב-CommitOptions ומחזיר ספירה של 6 שינויים, כי אנחנו מוסיפים או מעדכנים 2 שורות ו-3 עמודות בכל שורה.

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#‎

ב-C#, נתוני קומיטים לא מוחזרים ישירות דרך ה-API. במקום זאת, הם נרשמים ברמת היומן Information על ידי היומן שמוגדר כברירת מחדל.

הקוד הבא מפעיל רישום ביומן של נתוני אישור לכל העסקאות על ידי הגדרת המאפיין LogCommitStats ב-SpannerConnectionStringBuilder לערך true. הקוד גם מטמיע כלי לרישום פעולות לדוגמה, ששומר הפניה לתגובת השליחה האחרונה. לאחר מכן, המערכת מאחזרת את MutationCount מהתשובה הזו ומציגה אותו.


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

הקוד הבא מגדיר את הדגל ReturnCommitStats ומדפיס את מספר השינויים כשהעסקה מתבצעת בהצלחה.


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

הקוד הבא מגדיר את הדגל returnCommitStats ומחזיר ספירת מוטציות של 6, כי אנחנו מוסיפים או מעדכנים 2 שורות ו-3 עמודות בכל שורה.

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

במקום להחזיר את נתוני השליחה ישירות דרך ה-API, ספריית הלקוח של Python מתעדת אותם באמצעות stdout ברמה Info.

הקוד הבא מאפשר רישום ביומן של נתונים סטטיסטיים לגבי ביצוע פעולות (commit) לכל העסקאות על ידי הגדרת database.log_commit_stats = True. הקוד גם מטמיע כלי לרישום ביומן לדוגמה, ששומר הפניה לתגובת השליחה האחרונה שנראתה. אחר כך, המערכת מאחזרת את mutation_count מהתשובה הזו ומציגה אותו.

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 (
                "extra" in kwargs
                and kwargs["extra"]
                and "commit_stats" in kwargs["extra"]
            ):
                self.last_commit_stats = kwargs["extra"]["commit_stats"]
            super().info(msg, *args, **kwargs)

    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

הקוד הבא מגדיר את הדגל return_commit_stats ומחזיר ספירת מוטציות של 6, כי אנחנו מוסיפים או מעדכנים 2 שורות ו-3 עמודות בכל שורה.

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

המאמרים הבאים