תחילת העבודה עם Spanner ב-ADO.NET

מטרות

במדריך הזה נסביר איך לבצע את השלבים הבאים באמצעות מנהל ההתקן של Spanner ADO.NET:

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

עלויות

במדריך הזה משתמשים ב-Spanner, רכיב שלGoogle Cloudשהשימוש בו כרוך בתשלום. למידע על עלות השימוש ב-Spanner, ראו תמחור.

לפני שמתחילים

מבצעים את השלבים שמפורטים בקטע הגדרה, שכוללים יצירה והגדרה של פרויקט Google Cloud כברירת מחדל, הפעלת החיוב, הפעלת Cloud Spanner API והגדרת OAuth 2.0 כדי לקבל פרטי כניסה לאימות לשימוש ב-Cloud Spanner API.

חשוב במיוחד להריץ את הפקודה gcloud auth application-default login כדי להגדיר את סביבת הפיתוח המקומית עם פרטי כניסה לאימות.

הכנת סביבת ADO.NET המקומית

  1. אם ‎.NET לא מותקן במחשב הפיתוח, מורידים ומתקינים אותו.

  2. משכפלים את המאגר לדוגמה ומעבירים אותו למכונה המקומית:

    git clone https://github.com/googleapis/dotnet-spanner-entity-framework.git
    
  3. עוברים לספרייה שמכילה את הקוד לדוגמה של מנהל ההתקן של Spanner ADO.NET:

    cd dotnet-spanner-entity-framework/spanner-ado-net/spanner-ado-net-getting-started-guide
    

יצירת מכונה

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

במאמר יצירת מכונה מוסבר איך ליצור מכונה של Spanner באמצעות אחת מהשיטות הבאות. אפשר לתת למכונה את השם test-instance כדי להשתמש בה עם נושאים אחרים במסמך הזה, שמתייחסים למכונה בשם test-instance.

  • Google Cloud CLI
  • מסוף Google Cloud
  • ספריית לקוח (C++‎,‏ C#‎,‏ Go,‏ Java,‏ Node.js,‏ PHP,‏ Python,‏ Ruby או Rust)

עיון בקבצים לדוגמה

מאגר הדוגמאות מכיל דוגמה שמראה איך להשתמש ב-Spanner עם ADO.NET.

עיינו בקובץ SampleRunner.cs, שבו מוסבר איך להשתמש ב-Spanner. הקוד מראה איך ליצור מסד נתונים חדש ולהשתמש בו. הנתונים משתמשים בסכימה לדוגמה שמוצגת בדף סכימה ומודל נתונים.

יצירת מסד נתונים

GoogleSQL

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

PostgreSQL

gcloud spanner databases create example-db --instance=test-instance \
  --database-dialect=POSTGRESQL

אמורה להופיע ההודעה:

Creating database...done.

יצירת טבלאות

הקוד הבא יוצר שתי טבלאות במסד הנתונים.

GoogleSQL

public static async Task CreateTables(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Create two tables in one batch on Spanner.
    var batch = connection.CreateBatch();
    batch.BatchCommands.Add("CREATE TABLE Singers (" +
                            "  SingerId   INT64 NOT NULL, " +
                            "  FirstName  STRING(1024), " +
                            "  LastName   STRING(1024), " +
                            "  SingerInfo BYTES(MAX) " +
                            ") PRIMARY KEY (SingerId)");
    batch.BatchCommands.Add("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");
    await batch.ExecuteNonQueryAsync();
    Console.WriteLine("Created Singers & Albums tables");
}

PostgreSQL

public static async Task CreateTables(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Create two tables in one batch on Spanner.
    var batch = connection.CreateBatch();
    batch.BatchCommands.Add("create table singers (" +
                            "  singer_id   bigint not null primary key, " +
                            "  first_name  varchar(1024), " +
                            "  last_name   varchar(1024), " +
                            "  singer_info bytea" +
                            ")");
    batch.BatchCommands.Add("create table albums (" +
                            "  singer_id     bigint not null, " +
                            "  album_id      bigint not null, " +
                            "  album_title   varchar, " +
                            "  primary key (singer_id, album_id)" +
                            ") interleave in parent singers on delete cascade");
    await batch.ExecuteNonQueryAsync();
    Console.WriteLine("Created Singers & Albums tables");
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run createtables projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run createtablespg projects/PROJECT_ID/instances/test-instance/databases/example-db

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

יצירת חיבור

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

GoogleSQL

/// <summary>
/// Create an ADO.NET connection to a Spanner database.
/// </summary>
/// <param name="connectionString">
/// A connection string in the format
/// 'Data Source=projects/my-project/instances/my-instance/databases/my-database'.
/// </param>
public static async Task CreateConnection(string connectionString)
{
    // Use a SpannerConnectionStringBuilder to construct a connection string.
    // The SpannerConnectionStringBuilder contains properties for the most
    // used connection string variables.
    var builder = new SpannerConnectionStringBuilder(connectionString)
    {
        // Sets the default isolation level that should be used for all
        // read/write transactions on this connection.
        DefaultIsolationLevel = IsolationLevel.RepeatableRead,

        // The Options property can be used to set any connection property
        // as a key-value pair.
        Options = "statement_cache_size=2000"
    };

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

    await using var command = connection.CreateCommand();
    command.CommandText = "SELECT 'Hello World' as Message";
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"Greeting from Spanner: {reader.GetString(0)}");
    }
}

PostgreSQL

/// <summary>
/// Create an ADO.NET connection to a Spanner PostgreSQL database.
/// </summary>
/// <param name="connectionString">
/// A connection string in the format
/// 'Data Source=projects/my-project/instances/my-instance/databases/my-database'.
/// </param>
public static async Task CreateConnection(string connectionString)
{
    // Use a SpannerConnectionStringBuilder to construct a connection string.
    // The SpannerConnectionStringBuilder contains properties for the most
    // used connection string variables.
    var builder = new SpannerConnectionStringBuilder(connectionString)
    {
        // Sets the default isolation level that should be used for all
        // read/write transactions on this connection.
        DefaultIsolationLevel = IsolationLevel.RepeatableRead,

        // The Options property can be used to set any connection property
        // as a key-value pair.
        Options = "statement_cache_size=2000"
    };

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

    await using var command = connection.CreateCommand();
    command.CommandText = "SELECT 'Hello World' as Message";
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"Greeting from Spanner: {reader.GetString(0)}");
    }
}

כתיבת נתונים באמצעות DML

אפשר להוסיף נתונים באמצעות שפת טיפול בנתונים (DML) בטרנזקציית קריאה-כתיבה.

משתמשים ב-method‏ DbCommand#ExecuteNonQuery כדי להריץ פקודת DML.

GoogleSQL

public static async Task WriteDataWithDml(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Add 4 rows in one statement.
    // The ADO.NET driver supports positional query parameters.
    await using var command = connection.CreateCommand();
    command.CommandText = "INSERT INTO Singers (SingerId, FirstName, LastName) " +
                          "VALUES (?, ?, ?), (?, ?, ?), " +
                          "       (?, ?, ?), (?, ?, ?)";
    command.Parameters.Add(12);
    command.Parameters.Add("Melissa");
    command.Parameters.Add("Garcia");

    command.Parameters.Add(13);
    command.Parameters.Add("Russel");
    command.Parameters.Add("Morales");

    command.Parameters.Add(14);
    command.Parameters.Add("Jacqueline");
    command.Parameters.Add("Long");

    command.Parameters.Add(15);
    command.Parameters.Add("Dylan");
    command.Parameters.Add("Shaw");

    var affected = await command.ExecuteNonQueryAsync();
    Console.WriteLine($"{affected} record(s) inserted.");
}

PostgreSQL

public static async Task WriteDataWithDml(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Add 4 rows in one statement.
    // The ADO.NET driver supports positional query parameters.
    await using var command = connection.CreateCommand();
    command.CommandText = "insert into singers (singer_id, first_name, last_name) " +
                          "VALUES (?, ?, ?), (?, ?, ?), " +
                          "       (?, ?, ?), (?, ?, ?)";
    command.Parameters.Add(12);
    command.Parameters.Add("Melissa");
    command.Parameters.Add("Garcia");

    command.Parameters.Add(13);
    command.Parameters.Add("Russel");
    command.Parameters.Add("Morales");

    command.Parameters.Add(14);
    command.Parameters.Add("Jacqueline");
    command.Parameters.Add("Long");

    command.Parameters.Add(15);
    command.Parameters.Add("Dylan");
    command.Parameters.Add("Shaw");

    var affected = await command.ExecuteNonQueryAsync();
    Console.WriteLine($"{affected} record(s) inserted.");
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run dmlwrite projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run dmlwritepg projects/PROJECT_ID/instances/test-instance/databases/example-db

התוצאה צריכה להראות:

4 records inserted.

כתיבת נתונים באמצעות מוטציות

אפשר גם להוסיף נתונים באמצעות מוטציות.

אפשר להוסיף נתונים באמצעות השיטה batch.CreateInsertCommand(), שיוצרת SpannerBatchCommand חדש כדי להוסיף שורות לטבלה. השיטה SpannerBatchCommand.ExecuteNonQueryAsync() מוסיפה שורות חדשות לטבלה.

הקוד הבא מראה איך לכתוב נתונים באמצעות מוטציות:

GoogleSQL

struct Singer
{
    internal long SingerId;
    internal string FirstName;
    internal string LastName;
}

struct Album
{
    internal long SingerId;
    internal long AlbumId;
    internal string Title;
}

public static async Task WriteDataWithMutations(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    Singer[] singers =
    [
        new() {SingerId=1, FirstName = "Marc", LastName = "Richards"},
        new() {SingerId=2, FirstName = "Catalina", LastName = "Smith"},
        new() {SingerId=3, FirstName = "Alice", LastName = "Trentor"},
        new() {SingerId=4, FirstName = "Lea", LastName = "Martin"},
        new() {SingerId=5, FirstName = "David", LastName = "Lomond"},
    ];
    Album[] albums =
    [
        new() {SingerId = 1, AlbumId = 1, Title = "Total Junk"},
        new() {SingerId = 1, AlbumId = 2, Title = "Go, Go, Go"},
        new() {SingerId = 2, AlbumId = 1, Title = "Green"},
        new() {SingerId = 2, AlbumId = 2, Title = "Forever Hold Your Peace"},
        new() {SingerId = 2, AlbumId = 3, Title = "Terrified"},
    ];
    var batch = connection.CreateBatch();
    foreach (var singer in singers)
    {
        // The name of a parameter must correspond with a column name.
        var command = batch.CreateInsertCommand("Singers");
        command.AddParameter("SingerId", singer.SingerId);
        command.AddParameter("FirstName", singer.FirstName);
        command.AddParameter("LastName", singer.LastName);
        batch.BatchCommands.Add(command);
    }
    foreach (var album in albums)
    {
        // The name of a parameter must correspond with a column name.
        var command = batch.CreateInsertCommand("Albums");
        command.AddParameter("SingerId", album.SingerId);
        command.AddParameter("AlbumId", album.AlbumId);
        command.AddParameter("AlbumTitle", album.Title);
        batch.BatchCommands.Add(command);
    }
    var affected = await batch.ExecuteNonQueryAsync();
    Console.WriteLine($"Inserted {affected} rows.");
}

PostgreSQL

struct Singer
{
    internal long SingerId;
    internal string FirstName;
    internal string LastName;
}

struct Album
{
    internal long SingerId;
    internal long AlbumId;
    internal string Title;
}

public static async Task WriteDataWithMutations(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    Singer[] singers =
    [
        new() {SingerId=1, FirstName = "Marc", LastName = "Richards"},
        new() {SingerId=2, FirstName = "Catalina", LastName = "Smith"},
        new() {SingerId=3, FirstName = "Alice", LastName = "Trentor"},
        new() {SingerId=4, FirstName = "Lea", LastName = "Martin"},
        new() {SingerId=5, FirstName = "David", LastName = "Lomond"},
    ];
    Album[] albums =
    [
        new() {SingerId = 1, AlbumId = 1, Title = "Total Junk"},
        new() {SingerId = 1, AlbumId = 2, Title = "Go, Go, Go"},
        new() {SingerId = 2, AlbumId = 1, Title = "Green"},
        new() {SingerId = 2, AlbumId = 2, Title = "Forever Hold Your Peace"},
        new() {SingerId = 2, AlbumId = 3, Title = "Terrified"},
    ];
    var batch = connection.CreateBatch();
    foreach (var singer in singers)
    {
        // The name of a parameter must correspond with a column name.
        var command = batch.CreateInsertCommand("singers");
        command.AddParameter("singer_id", singer.SingerId);
        command.AddParameter("first_name", singer.FirstName);
        command.AddParameter("last_name", singer.LastName);
        batch.BatchCommands.Add(command);
    }
    foreach (var album in albums)
    {
        // The name of a parameter must correspond with a column name.
        var command = batch.CreateInsertCommand("albums");
        command.AddParameter("singer_id", album.SingerId);
        command.AddParameter("album_id", album.AlbumId);
        command.AddParameter("album_title", album.Title);
        batch.BatchCommands.Add(command);
    }
    var affected = await batch.ExecuteNonQueryAsync();
    Console.WriteLine($"Inserted {affected} rows.");
}

מריצים את הדוגמה הבאה באמצעות הארגומנט write:

GoogleSQL

dotnet run write projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run writepg projects/PROJECT_ID/instances/test-instance/databases/example-db

הרצת שאילתות על נתונים באמצעות SQL

‫Spanner תומך בממשק SQL לקריאת נתונים, שאפשר לגשת אליו בשורת הפקודה באמצעות Google Cloud CLI או באופן פרוגרמטי באמצעות מנהל ההתקן של Spanner ADO.NET.

בשורת הפקודה

מריצים את הצהרת ה-SQL הבאה כדי לקרוא את הערכים של כל העמודות מהטבלה Albums:

GoogleSQL

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

תחביר Pipe ב-GoogleSQL

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

PostgreSQL

gcloud spanner databases execute-sql example-db --instance=test-instance \
    --sql='SELECT singer_id, album_id, album_title FROM albums'

בתוצאה רואים:

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

שימוש במנהל ההתקן של Spanner ADO.NET

בנוסף להרצת הצהרת SQL בשורת הפקודה, אתם יכולים להנפיק את אותה הצהרת SQL באופן פרוגרמטי באמצעות מנהל ההתקן של Spanner ADO.NET.

ה-methods הבאות משמשות להרצת שאילתת SQL:

  • ה-method‏ ExecuteReader במחלקה DbCommand: משמשת להרצת הצהרת SQL שמחזירה שורות, כמו שאילתה או פקודת DML עם סעיף THEN RETURN.
  • המחלקה DbDataReader: משתמשים בה כדי לגשת לנתונים שמוחזרים על ידי הצהרת SQL.

בדוגמה הבאה משתמשים ב-ExecuteReaderAsync:

GoogleSQL

public static async Task QueryData(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "SELECT SingerId, AlbumId, AlbumTitle " +
                          "FROM Albums " +
                          "ORDER BY SingerId, AlbumId";
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"{reader["SingerId"]} {reader["AlbumId"]} {reader["AlbumTitle"]}");
    }
}

PostgreSQL

public static async Task QueryData(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "SELECT singer_id, album_id, album_title " +
                          "FROM albums " +
                          "ORDER BY singer_id, album_id";
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"{reader["singer_id"]} {reader["album_id"]} {reader["album_title"]}");
    }
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run query projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run querypg projects/PROJECT_ID/instances/test-instance/databases/example-db

התוצאה צריכה להראות:

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

שאילתה באמצעות פרמטר SQL

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

הנה דוגמה לשימוש בפרמטר בסעיף WHERE כדי לשלוח שאילתה על רשומות שמכילות ערך ספציפי של LastName.

מנהל ההתקן של Spanner ADO.NET תומך גם בפרמטרים של שאילתות לפי מיקום וגם בפרמטרים של שאילתות לפי שם. הסימן ? בהצהרת SQL מציין פרמטר של שאילתה לפי מיקום. מוסיפים ערכים של פרמטרים של שאילתה ל-Parameters של ה-DbCommand. לדוגמה:

GoogleSQL

public static async Task QueryDataWithParameter(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "SELECT SingerId, FirstName, LastName " +
                          "FROM Singers " +
                          "WHERE LastName = ?";
    command.Parameters.Add("Garcia");
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"{reader["SingerId"]} {reader["FirstName"]} {reader["LastName"]}");
    }
}

PostgreSQL

public static async Task QueryDataWithParameter(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "SELECT singer_id, first_name, last_name " +
                          "FROM singers " +
                          "WHERE last_name = ?";
    command.Parameters.Add("Garcia");
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"{reader["singer_id"]} {reader["first_name"]} {reader["last_name"]}");
    }
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run querywithparameter projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run querywithparameterpg projects/PROJECT_ID/instances/test-instance/databases/example-db

בתוצאה רואים:

12 Melissa Garcia

עדכון הסכימה של מסד הנתונים

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

הוספת עמודה

אפשר להוסיף עמודה בשורת הפקודה באמצעות Google Cloud CLI או באופן פרוגרמטי באמצעות מנהל ההתקן של Spanner ADO.NET.

בשורת הפקודה

משתמשים בפקודה הבאה של ALTER TABLE כדי להוסיף את העמודה החדשה לטבלה:

GoogleSQL

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

PostgreSQL

gcloud spanner databases ddl update example-db --instance=test-instance \
    --ddl='alter table albums add column marketing_budget bigint'

אמורה להופיע ההודעה:

Schema updating...done.

שימוש במנהל ההתקן של Spanner ADO.NET

משתמשים ב-method‏ ExecuteNonQueryAsync כדי לשנות את הסכימה:

GoogleSQL

public static async Task AddColumn(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "ALTER TABLE Albums ADD COLUMN MarketingBudget INT64";
    await command.ExecuteNonQueryAsync();

    Console.WriteLine("Added MarketingBudget column");
}

PostgreSQL

public static async Task AddColumn(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "alter table albums add column marketing_budget bigint";
    await command.ExecuteNonQueryAsync();

    Console.WriteLine("Added marketing_budget column");
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run addcolumn projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run addcolumnpg projects/PROJECT_ID/instances/test-instance/databases/example-db

בתוצאה רואים:

Added MarketingBudget column.

הפעלת אצווה של DDL

מומלץ לבצע כמה שינויים בסכימה באצווה אחת. משתמשים ב-method‏ CreateBatch של ADO.NET כדי ליצור אצווה. בדוגמה הבאה נוצרות שתי טבלאות באצווה אחת:

GoogleSQL

public static async Task DdlBatch(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Executing multiple DDL statements as one batch is
    // more efficient than executing each statement individually.
    var batch = connection.CreateBatch();
    batch.BatchCommands.Add(
        "CREATE TABLE Venues (" +
        "  VenueId     INT64 NOT NULL, " +
        "  Name        STRING(1024), " +
        "  Description JSON, " +
        ") PRIMARY KEY (VenueId)");
    batch.BatchCommands.Add(
        "CREATE TABLE Concerts (" +
        "  ConcertId INT64 NOT NULL, " +
        "  VenueId   INT64 NOT NULL, " +
        "  SingerId  INT64 NOT NULL, " +
        "  StartTime TIMESTAMP, " +
        "  EndTime   TIMESTAMP, " +
        "  CONSTRAINT Fk_Concerts_Venues " +
        "    FOREIGN KEY (VenueId) REFERENCES Venues (VenueId), " +
        "  CONSTRAINT Fk_Concerts_Singers " +
        "    FOREIGN KEY (SingerId) REFERENCES Singers (SingerId), " +
        ") PRIMARY KEY (ConcertId)");
    await batch.ExecuteNonQueryAsync();

    Console.WriteLine("Added Venues and Concerts tables");
}

PostgreSQL

public static async Task DdlBatch(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Executing multiple DDL statements as one batch is
    // more efficient than executing each statement individually.
    var batch = connection.CreateBatch();
    batch.BatchCommands.Add(
        "create table venues (" +
        "  venue_id    bigint not null primary key, " +
        "  name        varchar(1024), " +
        "  description jsonb" +
        ")");
    batch.BatchCommands.Add(
        "create table concerts (" +
        "  concert_id bigint not null primary key, " +
        "  venue_id   bigint not null, " +
        "  singer_id  bigint not null, " +
        "  start_time timestamptz, " +
        "  end_time   timestamptz, " +
        "  constraint fk_concerts_venues foreign key " +
        "    (venue_id) references venues (venue_id), " +
        "  constraint fk_concerts_singers foreign key " +
        "    (singer_id) references singers (singer_id)" +
        ")");
    await batch.ExecuteNonQueryAsync();

    Console.WriteLine("Added Venues and Concerts tables");
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run ddlbatch projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run ddlbatchpg projects/PROJECT_ID/instances/test-instance/databases/example-db

בתוצאה רואים:

Added Venues and Concerts tables.

כתיבת נתונים בעמודה החדשה

הקוד הבא כותב נתונים בעמודה החדשה. היא מגדירה את MarketingBudget לערך 100000 בשורה עם מפתח השורה Albums(1, 1), ולערך 500000 בשורה עם מפתח השורה Albums(2, 2).

GoogleSQL

public static async Task UpdateDataWithMutations(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    (long SingerId, long AlbumId, long MarketingBudget)[] albums = [
        (1L, 1L, 100000L),
        (2L, 2L, 500000L),
    ];
    // Use a batch to update two rows in one round-trip.
    var batch = connection.CreateBatch();
    foreach (var album in albums)
    {
        // This creates a command that will use a mutation to update the row.
        var command = batch.CreateUpdateCommand("Albums");
        command.AddParameter("SingerId", album.SingerId);
        command.AddParameter("AlbumId", album.AlbumId);
        command.AddParameter("MarketingBudget", album.MarketingBudget);
        batch.BatchCommands.Add(command);
    }
    var affected = await batch.ExecuteNonQueryAsync();
    Console.WriteLine($"Updated {affected} albums.");
}

PostgreSQL

public static async Task UpdateDataWithMutations(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    (long SingerId, long AlbumId, long MarketingBudget)[] albums = [
        (1L, 1L, 100000L),
        (2L, 2L, 500000L),
    ];
    // Use a batch to update two rows in one round-trip.
    var batch = connection.CreateBatch();
    foreach (var album in albums)
    {
        // This creates a command that will use a mutation to update the row.
        var command = batch.CreateUpdateCommand("albums");
        command.AddParameter("singer_id", album.SingerId);
        command.AddParameter("album_id", album.AlbumId);
        command.AddParameter("marketing_budget", album.MarketingBudget);
        batch.BatchCommands.Add(command);
    }
    var affected = await batch.ExecuteNonQueryAsync();
    Console.WriteLine($"Updated {affected} albums.");
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run update projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run updatepg projects/PROJECT_ID/instances/test-instance/databases/example-db

בתוצאה רואים:

Updated 2 albums

אפשר גם להריץ שאילתת SQL כדי לאחזר את הערכים שכתבתם.

בדוגמה הבאה משתמשים ב-method‏ ExecuteReaderAsync כדי להריץ שאילתה:

GoogleSQL

public static async Task QueryNewColumn(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "SELECT SingerId, AlbumId, MarketingBudget " +
                          "FROM Albums " +
                          "ORDER BY SingerId, AlbumId";
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"{reader["SingerId"]} {reader["AlbumId"]} {reader["MarketingBudget"]}");
    }
}

PostgreSQL

public static async Task QueryNewColumn(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "select singer_id, album_id, marketing_budget " +
                          "from albums " +
                          "order by singer_id, album_id";
    await using var reader = await command.ExecuteReaderAsync();
    while (await reader.ReadAsync())
    {
        Console.WriteLine($"{reader["singer_id"]} {reader["album_id"]} {reader["marketing_budget"]}");
    }
}

כדי להריץ את השאילתה הזו, מריצים את הפקודה הבאה:

GoogleSQL

dotnet run querymarketingbudget projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run querymarketingbudgetpg projects/PROJECT_ID/instances/test-instance/databases/example-db

אמורה להופיע ההודעה:

1 1 100000
1 2 null
2 1 null
2 2 500000
2 3 null

עדכון נתונים

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

קוראים ל-connection.BeginTransactionAsync() כדי לבצע עסקאות קריאה-כתיבה ב-ADO.NET.

GoogleSQL

public static async Task WriteDataWithTransaction(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Transfer marketing budget from one album to another. We do it in a
    // transaction to ensure that the transfer is atomic.
    await using var transaction = await connection.BeginTransactionAsync();

    // The Spanner ADO.NET driver supports both positional and named
    // query parameters. This query uses named query parameters.
    const string selectSql =
        "SELECT MarketingBudget " +
        "FROM Albums " +
        "WHERE SingerId = @singerId and AlbumId = @albumId";
    // Get the marketing_budget of singer 2 / album 2.
    await using var command = connection.CreateCommand();
    command.CommandText = selectSql;
    command.Transaction = transaction;
    command.Parameters.AddWithValue("singerId", 2);
    command.Parameters.AddWithValue("albumId", 2);
    var budget2 = (long) (await command.ExecuteScalarAsync() ?? 0L);

    const long transfer = 20000L;
    // The transaction will only be committed if this condition still holds
    // at the time of commit. Otherwise, the transaction will be aborted.
    if (budget2 >= transfer)
    {
        // Get the marketing_budget of singer 1 / album 1.
        command.Parameters["singerId"].Value = 1;
        command.Parameters["albumId"].Value = 1;
        var budget1 = (long) (await command.ExecuteScalarAsync() ?? 0L);

        // Transfer part of the marketing budget of Album 2 to Album 1.
        budget1 += transfer;
        budget2 -= transfer;
        const string updateSql =
            "UPDATE Albums " +
            "SET MarketingBudget = @budget " +
            "WHERE SingerId = @singerId and AlbumId = @albumId";
        // Create a DML batch and execute it as part of the current transaction.
        var batch = connection.CreateBatch();
        batch.Transaction = transaction;

        // Update the marketing budgets of both Album 1 and Album 2 in a batch.
        (long SingerId, long AlbumId, long MarketingBudget)[] budgets = [
            new (1L, 1L, budget1),
            new (2L, 2L, budget2),
        ];
        foreach (var budget in budgets)
        {
            var batchCommand = batch.CreateBatchCommand();
            batchCommand.CommandText = updateSql;
            var singerIdParameter = batchCommand.CreateParameter();
            singerIdParameter.ParameterName = "singerId";
            singerIdParameter.Value = budget.SingerId;
            batchCommand.Parameters.Add(singerIdParameter);
            var albumIdParameter = batchCommand.CreateParameter();
            albumIdParameter.ParameterName = "albumId";
            albumIdParameter.Value = budget.AlbumId;
            batchCommand.Parameters.Add(albumIdParameter);
            var marketingBudgetParameter = batchCommand.CreateParameter();
            marketingBudgetParameter.ParameterName = "budget";
            marketingBudgetParameter.Value = budget.MarketingBudget;
            batchCommand.Parameters.Add(marketingBudgetParameter);
            batch.BatchCommands.Add(batchCommand);
        }
        var affected = await batch.ExecuteNonQueryAsync();
        // The batch should update 2 rows.
        if (affected != 2)
        {
            await transaction.RollbackAsync();
            throw new InvalidOperationException($"Unexpected num affected: {affected}");
        }
    }
    // Commit the transaction.
    await transaction.CommitAsync();
    Console.WriteLine("Transferred marketing budget from Album 2 to Album 1");
}

PostgreSQL

public static async Task WriteDataWithTransaction(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Transfer marketing budget from one album to another. We do it in a
    // transaction to ensure that the transfer is atomic.
    await using var transaction = await connection.BeginTransactionAsync();

    // The Spanner ADO.NET driver supports both positional and named
    // query parameters. This query uses named query parameters.
    const string selectSql =
        "SELECT marketing_budget " +
        "FROM albums " +
        "WHERE singer_id = $1 and album_id = $2";
    // Get the marketing_budget of singer 2 / album 2.
    await using var command = connection.CreateCommand();
    command.CommandText = selectSql;
    command.Transaction = transaction;
    command.Parameters.AddWithValue("p1", 2);
    command.Parameters.AddWithValue("p2", 2);
    var budget2 = (long) (await command.ExecuteScalarAsync() ?? 0L);

    const long transfer = 20000L;
    // The transaction will only be committed if this condition still holds
    // at the time of commit. Otherwise, the transaction will be aborted.
    if (budget2 >= transfer)
    {
        // Get the marketing_budget of singer 1 / album 1.
        command.Parameters["p1"].Value = 1;
        command.Parameters["p2"].Value = 1;
        var budget1 = (long) (await command.ExecuteScalarAsync() ?? 0L);

        // Transfer part of the marketing budget of Album 2 to Album 1.
        budget1 += transfer;
        budget2 -= transfer;
        const string updateSql =
            "UPDATE albums " +
            "SET marketing_budget = $1 " +
            "WHERE singer_id = $2 and album_id = $3";
        // Create a DML batch and execute it as part of the current transaction.
        var batch = connection.CreateBatch();
        batch.Transaction = transaction;

        // Update the marketing budgets of both Album 1 and Album 2 in a batch.
        (long SingerId, long AlbumId, long MarketingBudget)[] budgets = [
            new (1L, 1L, budget1),
            new (2L, 2L, budget2),
        ];
        foreach (var budget in budgets)
        {
            var batchCommand = batch.CreateBatchCommand();
            batchCommand.CommandText = updateSql;
            var marketingBudgetParameter = batchCommand.CreateParameter();
            marketingBudgetParameter.ParameterName = "p1";
            marketingBudgetParameter.Value = budget.MarketingBudget;
            batchCommand.Parameters.Add(marketingBudgetParameter);
            var singerIdParameter = batchCommand.CreateParameter();
            singerIdParameter.ParameterName = "p2";
            singerIdParameter.Value = budget.SingerId;
            batchCommand.Parameters.Add(singerIdParameter);
            var albumIdParameter = batchCommand.CreateParameter();
            albumIdParameter.ParameterName = "p3";
            albumIdParameter.Value = budget.AlbumId;
            batchCommand.Parameters.Add(albumIdParameter);
            batch.BatchCommands.Add(batchCommand);
        }
        var affected = await batch.ExecuteNonQueryAsync();
        // The batch should update 2 rows.
        if (affected != 2)
        {
            await transaction.RollbackAsync();
            throw new InvalidOperationException($"Unexpected num affected: {affected}");
        }
    }
    // Commit the transaction.
    await transaction.CommitAsync();
    Console.WriteLine("Transferred marketing budget from Album 2 to Album 1");
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run writewithtransactionusingdml projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run writewithtransactionusingdmlpg projects/PROJECT_ID/instances/test-instance/databases/example-db

תגי עסקה ותגי בקשה

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

GoogleSQL

public static async Task Tags(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    const long singerId = 1L;
    const long albumId = 1L;

    await using var transaction = await connection.BeginTransactionAsync();
    // Set a tag on the transaction before executing any statements.
    transaction.Tag = "example-tx-tag";

    await using var command = connection.CreateCommand();
    command.Transaction = transaction;
    command.Tag = "query-marketing-budget";
    command.CommandText =
        "SELECT MarketingBudget " +
        "FROM Albums " +
        "WHERE SingerId=? and AlbumId=?";
    command.Parameters.Add(singerId);
    command.Parameters.Add(albumId);
    var budget = (long)(await command.ExecuteScalarAsync() ?? 0L);

    // Reduce the marketing budget by 10% if it is more than 1,000.
    if (budget > 1000)
    {
        budget -= budget / 10;
        await using var updateCommand = connection.CreateCommand();
        updateCommand.Transaction = transaction;
        updateCommand.Tag = "reduce-marketing-budget";
        updateCommand.CommandText =
            "UPDATE Albums SET MarketingBudget=@budget WHERE SingerId=@singerId AND AlbumId=@albumId";
        updateCommand.Parameters.AddWithValue("budget", budget);
        updateCommand.Parameters.AddWithValue("singerId", singerId);
        updateCommand.Parameters.AddWithValue("albumId", albumId);
        await updateCommand.ExecuteNonQueryAsync();
    }
    // Commit the transaction.
    await transaction.CommitAsync();
    Console.WriteLine("Reduced marketing budget");
}

PostgreSQL

public static async Task Tags(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    const long singerId = 1L;
    const long albumId = 1L;

    await using var transaction = await connection.BeginTransactionAsync();
    // Set a tag on the transaction before executing any statements.
    transaction.Tag = "example-tx-tag";

    await using var command = connection.CreateCommand();
    command.Transaction = transaction;
    command.Tag = "query-marketing-budget";
    command.CommandText =
        "select marketing_budget " +
        "from albums " +
        "where singer_id=? and album_id=?";
    command.Parameters.Add(singerId);
    command.Parameters.Add(albumId);
    var budget = (long)(await command.ExecuteScalarAsync() ?? 0L);

    // Reduce the marketing budget by 10% if it is more than 1,000.
    if (budget > 1000)
    {
        budget -= budget / 10;
        await using var updateCommand = connection.CreateCommand();
        updateCommand.Transaction = transaction;
        updateCommand.Tag = "reduce-marketing-budget";
        updateCommand.CommandText =
            "update albums set marketing_budget=$1 where singer_id=$2 and album_id=$3";
        updateCommand.Parameters.Add(budget);
        updateCommand.Parameters.Add(singerId);
        updateCommand.Parameters.Add(albumId);
        await updateCommand.ExecuteNonQueryAsync();
    }
    // Commit the transaction.
    await transaction.CommitAsync();
    Console.WriteLine("Reduced marketing budget");
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run tags projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run tagspg projects/PROJECT_ID/instances/test-instance/databases/example-db

אחזור נתונים באמצעות עסקאות לקריאה בלבד

נניח שאתם רוצים לבצע יותר מקריאה אחת באותה חותמת זמן. עסקאות לקריאה בלבד צופות בתחילית עקבית של היסטוריית ה-commit של העסקה, כך שהאפליקציה תמיד מקבלת נתונים עקביים. קוראים ל-connection.BeginReadOnlyTransactionAsync() כדי לבצע עסקה לקריאה בלבד.

כך מריצים שאילתה ומבצעים קריאה באותה עסקה לקריאה בלבד:

GoogleSQL

public static async Task ReadOnlyTransaction(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Start a read-only transaction on this connection.
    await using var transaction = await connection.BeginReadOnlyTransactionAsync();

    await using var command = connection.CreateCommand();
    command.Transaction = transaction;
    command.CommandText = "SELECT SingerId, AlbumId, AlbumTitle " +
                          "FROM Albums " +
                          "ORDER BY SingerId, AlbumId";
    await using (var reader = await command.ExecuteReaderAsync())
    {
        while (await reader.ReadAsync())
        {
            Console.WriteLine(
                $"{reader["SingerId"]} {reader["AlbumId"]} {reader["AlbumTitle"]}");
        }
    }

    // Execute another query using the same read-only transaction.
    command.CommandText = "SELECT SingerId, AlbumId, AlbumTitle " +
                          "FROM Albums " +
                          "ORDER BY AlbumTitle";
    await using (var reader = await command.ExecuteReaderAsync())
    {
        while (await reader.ReadAsync())
        {
            Console.WriteLine(
                $"{reader["SingerId"]} {reader["AlbumId"]} {reader["AlbumTitle"]}");
        }
    }

    // End the read-only transaction by calling Commit.
    await transaction.CommitAsync();
}

PostgreSQL

public static async Task ReadOnlyTransaction(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Start a read-only transaction on this connection.
    await using var transaction = await connection.BeginReadOnlyTransactionAsync();

    await using var command = connection.CreateCommand();
    command.Transaction = transaction;
    command.CommandText = "SELECT SingerId, AlbumId, AlbumTitle " +
                          "FROM Albums " +
                          "ORDER BY SingerId, AlbumId";
    await using (var reader = await command.ExecuteReaderAsync())
    {
        while (await reader.ReadAsync())
        {
            Console.WriteLine(
                $"{reader["SingerId"]} {reader["AlbumId"]} {reader["AlbumTitle"]}");
        }
    }

    // Execute another query using the same read-only transaction.
    command.CommandText = "SELECT SingerId, AlbumId, AlbumTitle " +
                          "FROM Albums " +
                          "ORDER BY AlbumTitle";
    await using (var reader = await command.ExecuteReaderAsync())
    {
        while (await reader.ReadAsync())
        {
            Console.WriteLine(
                $"{reader["SingerId"]} {reader["AlbumId"]} {reader["AlbumTitle"]}");
        }
    }

    // End the read-only transaction by calling Commit.
    await transaction.CommitAsync();
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run readonlytransaction projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run readonlytransactionpg projects/PROJECT_ID/instances/test-instance/databases/example-db

בתוצאה רואים:

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

‫DML מחולק למחיצות

שפת הטיפול בנתונים (DML) מחולקים למחיצות מיועדת לסוגים הבאים של עדכונים ומחיקות בכמות גדולה:

  • ניקיון תקופתי ואיסוף אשפה.
  • מילוי עמודות חדשות בערכי ברירת מחדל.

GoogleSQL

public static async Task PartitionedDml(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Enable Partitioned DML on this connection.
    await using var command = connection.CreateCommand();
    command.CommandText = "SET AUTOCOMMIT_DML_MODE='PARTITIONED_NON_ATOMIC'";
    await command.ExecuteNonQueryAsync();

    // Back-fill a default value for the MarketingBudget column.
    command.CommandText = "UPDATE Albums SET MarketingBudget=0 WHERE MarketingBudget IS NULL";
    var affected = await command.ExecuteNonQueryAsync();

    // Partitioned DML returns the minimum number of records that were affected.
    Console.WriteLine($"Updated at least {affected} albums");

    // Reset the value for AUTOCOMMIT_DML_MODE to its default.
    command.CommandText = "RESET AUTOCOMMIT_DML_MODE";
    await command.ExecuteNonQueryAsync();
}

PostgreSQL

public static async Task PartitionedDml(string connectionString)
{
    await using var connection = new SpannerConnection(connectionString);
    await connection.OpenAsync();

    // Enable Partitioned DML on this connection.
    await using var command = connection.CreateCommand();
    command.CommandText = "set autocommit_dml_mode='partitioned_non_atomic'";
    await command.ExecuteNonQueryAsync();

    // Back-fill a default value for the MarketingBudget column.
    command.CommandText = "update albums set marketing_budget=0 where marketing_budget is null";
    var affected = await command.ExecuteNonQueryAsync();

    // Partitioned DML returns the minimum number of records that were affected.
    Console.WriteLine($"Updated at least {affected} albums");

    // Reset the value for autocommit_dml_mode to its default.
    command.CommandText = "reset autocommit_dml_mode";
    await command.ExecuteNonQueryAsync();
}

מריצים את הדוגמה באמצעות הפקודה הבאה:

GoogleSQL

dotnet run pdml projects/PROJECT_ID/instances/test-instance/databases/example-db

PostgreSQL

dotnet run pdmlpg projects/PROJECT_ID/instances/test-instance/databases/example-db

הסרת המשאבים

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

מחיקת מסד הנתונים

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

בשורת הפקודה

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

באמצעות מסוף Google Cloud

  1. נכנסים לדף Spanner Instances במסוף Google Cloud .

    כניסה לדף Instances

  2. לוחצים על המופע.

  3. לוחצים על מסד הנתונים שרוצים למחוק.

  4. בדף Database details, לוחצים על Delete.

  5. מאשרים שרוצים למחוק את מסד הנתונים ולוחצים על מחיקה.

מחיקת המכונה

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

בשורת הפקודה

gcloud spanner instances delete test-instance

באמצעות מסוף Google Cloud

  1. נכנסים לדף Spanner Instances במסוף Google Cloud .

    כניסה לדף Instances

  2. לוחצים על המכונה.

  3. לוחצים על Delete.

  4. מאשרים שרוצים למחוק את המכונה ולוחצים על Delete.

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