フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

【新規ツール探し】Spanner の DDL を yaml で管理できる「splanter」

  • 記事作成日:2022/12/12

情報

名前 URL
Github https://github.com/kauche/splanter
公式サイト https://note.com/kauche/n/ne033cde0c9ea
デモサイト
開発母体 カウシェ
version 0.1.0
言語 Go
価格 無料
ライセンス MIT

何ができるもの?

  • YAML で DML を定義することで、冪等性のあるテーブルデータを splanter で用意できる

利用シーン

開発環境での利用を目的として開発していますが、「データを Insert (or Update) する」という性質から、「動的には更新されないマスターデータ」などを更新する用途で本番環境でも利用できます。

登場背景

splanter は「テストや動作確認で利用する開発・ローカル環境向けのデータを YAML で記述してリポジトリにコミットし、開発者間で共有したい」というモチベーションから開発しました。

所感

使い方

今回のコード - framinal-new-tools/splanter at main · lirlia/framinal-new-tools

インストール

Release v0.1.0 · kauche/splanter からダウンロード

もしくは go install github.com/kauche/splanter@latest

準備

以下の設定で db を作っておきます。

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
) PRIMARY KEY (SingerId);

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;

ddls 配下に以下のファイルを配置します。

Singers.yaml

- SingerId: '1'
  FirstName: 'Marc'
  LastName: 'Richards'

- SingerId: '2'
  FirstName: 'Catalina'
  LastName: 'Smith'

Albums.yaml

- SingerId: '1'
  AlbumId: '1'
  AlbumTitle: 'Total Junk'

- SingerId: '1'
  AlbumId: '2'
  AlbumTitle: 'Go, Go, Go'

- SingerId: '2'
  AlbumId: '3'
  AlbumTitle: 'Green'

- SingerId: '2'
  AlbumId: '4'
  AlbumTitle: 'Forever Hold Your Peace'

ディレクトリ構成はこれ。

.
├── ddls
│  ├── Albums.yaml
│  └── Singers.yaml
├── docker-compose.yml
├── schemas
│  └── db.sql
└── splanter

inset してみる

insert 前

❯ ./splanter --project PJ_NAME --instance riddle --database test-db --directory ./ddls

実行するときちんとデータが入っていました。

複数回実行しても変化がないので、冪等性が保証されているようです。便利!

40,000 mutation を超える場合もいける?

Cloud Spanner のトランザクションあたりの更新回数が 2 倍に増加 | Google Cloud 公式ブログ

Spanner では一回のトランザクションにおいてどの程度の行数、列数、を更新できるのか?が mutation という単位で制限されています。 具体的な計算式はこちら。

Users テーブルを作って

CREATE TABLE Users (
  Id     INT64 NOT NULL,
) PRIMARY KEY (Id);

10万件のユーザ追加を試してみます。

- Id: 1
...

- Id: 100000

これを実行してみると、しばらくして mutation 制限に引っかかったので、現在ツールでは対応していないようです。

❯ ./splanter --project PJ_NAME --instance riddle --database test-db --directory ./ddls

failed to load data to spanner tables: failed to insert records: spanner: code = "InvalidArgument", desc = "The transaction contains too many mutations. Insert and update operations count with the multiplicity of the number of columns they affect. For example, inserting values into one key column and four non-key columns count as five mutations total for the insert. Delete and delete range operations count as one mutation regardless of the number of columns affected. The total mutation count includes any changes to indexes that the transaction generates. Please reduce the number of writes, or use fewer indexes. (Maximum number: 40000)"

コードを見てもそのまま Apply しているので、mutation 対応はされていないよう様子。

func (d *DB) Save(ctx context.Context, tables []*model.Table) error {
    if err := d.sortTablesByDependencies(ctx, tables); err != nil {
        return fmt.Errorf("failed to sort tables: %w", err)
    }


    var mutations []*spanner.Mutation
    for _, table := range tables {
        for _, records := range table.Records {
            mutations = append(mutations, spanner.InsertOrUpdateMap(table.Name, records.Values))
        }
    }


    if _, err := d.client.Apply(ctx, mutations, spanner.Priority(spannerpb.RequestOptions_PRIORITY_LOW)); err != nil {
        return fmt.Errorf("failed to insert records: %w", err)
    }


    return nil