MJHD

エモさ駆動開発

GoでSpannerを扱う際のポイント

そもそもSpannerって?

SpannerはGCPが提供する高可用性のあるリレーショナルデータベース。SQL文が使え、スキーマ定義・スキーマの変更・SELECT系のクエリを実行できる。(INSERT, UPDATE, DELETEは無い) プライマリーキーを適切に設定すれば、負荷に応じて自動でシャーディングを行ってくれる。トランザクションも使える。 この辺がよくまとまっている。 超実践 Cloud Spanner 設計講座

GoでSpannerを利用した開発を行う中で、何点かわかったことがあったのでそのまとめ。

CreateSessionは遅い

Spannerに対してリクエストを行うとき、まずCreateSessionというgRPCが走るのだが、これが500msぐらいかかるため、Spannerに対して初めてリクエストを送る際など遅延が発生する。 これを防ぐために、SessionPoolConfigを適切に設定する必要がある。 spanner - GoDoc SessionPoolConfigの値は、 https://cloud.google.com/spanner/docs/sessions この記事を見ながら設定すると良い。(Spannerはこの辺のドキュメントが全て日本語で読めるためありがたい…)

クエリの遅延が発生した場合、この辺の設定を見直すことをおすすめする。

DeleteでAllKeyは(基本的に)使えない

テーブル内の全データを削除したいと思ったとき、愚直に考えれば「DeleteにAllKeys渡せばいいんだろ」となるのだが、データ数が増えた場合にこの戦略は使えなくなる。 CloudSpannerは、変更系のクエリの影響範囲が20000件以内、という制限を持つ。これは、UPDATEやINSERTに関しては「影響を受ける列数が20000件以内」で、DELETEに関しては「影響を受ける行数が20000件以内」となる。あくまで「影響を受ける」件数であるため、20000件以上のデータを持つテーブルの初期化は、「一度消して作り直す」しか方法が無いらしい。

ALTERで追加するカラムにはNOT NULL制約が付けられない

SpannerのALTER文の文法にはしっかりと「NOT NULL」という規則が載っているのだが、 https://cloud.google.com/spanner/docs/data-definition-language#alter_table 実際には使うことができない。Spannerは標準で新しく作ったカラムにはNULLを入れるのだが、NOT NULL制約を指定すると矛盾が発生するため、指定することができない。

セカンダリインデックスの場合も、スプリットを意識したキーを選ぶ必要がある

SpannerのPKを選ぶ際、スプリットが入ることを意識してキーを選ぶ必要があるのはご承知の通りだと思うが、セカンダリインデックスについても、スプリットが入ることを意識し、ホットスポットが入らないようなキーを選ぶ必要がある。
ドキュメントにも明記されているのだが、セカンダリインデックスもテーブルとして実装される。よって、セカンダリインデックスに指定したキーは、そのテーブルの主キーとして使用され、スプリットもそのキーによって決められる。
よって、アクセスが集中しやすいテーブルでセカンダリインデックスの先頭にCommit Timestampなどの単調に増加・減少する値を設定した場合、ホットスポットが発生し、スケールしなくなる。

今後、また気づきが増えたタイミングで更新します。