読者です 読者をやめる 読者になる 読者になる

PostgreSQL勉強会@札幌に参加してきた

開催から2週間近くも経ってしまいましたが、PostgreSQL勉強会@札幌に参加させていただきました。

以下、私的まとめ等です。

@syachiさんの「削除フラグのはなし」(スライド

はじめに

論理削除でおこりがちなケースとして……

  • 削除フラグがあるのだから、リレーションは使わない、レコードも消さない。プログラム側で何とかするから、不整合は起こらない!
    • 将来的に、データ構造と蓄積されたレコードの整合性・正当性・有効性が不明瞭になりやすい。
    • データの矛盾や誤データをカバーするためのコードが増えていく。

データベースの基本は「矛盾を排除すること」。データベース側で削除フラグを利用するときに想定されそうな矛盾を極力排除し、付き合いやすいデータベースを維持するためにはどうするか。

生きているレコードは1件のみ。死んだレコードは複数件許可。こんなときは?

ユーザIDなどの本来一意なカラムに対して、有効な削除フラグが1件になるような部分インデックスが有効。

論理削除を伝播させたい時(例:削除されたユーザにひもづくレコードも削除としたい)は?

削除フラグを、bool値ではなく、「キー値が負のもの」などというルールにしてしまう。
削除動作として主キーに-1をかければ、外部キーで関連するものを変更できる。

いっそ削除テーブルに入れてしまいたい時は?

各テーブルのレコードが削除された事をトリガにして、関連するテーブルのレコードを削除テーブルに移動してしまう様なFUNCTIONを用意する。
テーブル名を一貫したルール(delete_xxx)にしておけば、類推も楽。

削除フラグは我々の中でも一番の小物……

業務分析や設計を怠ると、下書きフラグ・一時停止フラグなど、次なる強敵も。

@iakioさんの「XIDを周回させてみよう」(スライド

はじめに
  • PostgreSQLを長く使ってると、データが見えなくなってしまうXIDの周回問題が発生する仕様らしい
    • じゃあ発生する瞬間を見てみよう!
トランザクションIDとは

トランザクションごとに発行されるID。
このIDの大きさで、データベースに要求された各トランザクションの実行順番の整合性管理している。トランザクションIDは各テーブルに Xmin, Xmax という隠し属性的なカラムで管理されていて、SELECT文で閲覧可能。

ある環境化でXmin, Xmaxの値がオーバーラップすると、トランザクションが無効になる≒データが消失する。

PostgreSQLの自衛手段

トランザクションIDの逆転防止の為に、PostgreSQLには自衛手段が組み込まれている。

このため、通常利用などにおいては、周回問題を発生させるのは難しい。(逆に言えば安全)

周回問題を防ぐ為に運用側で意識することは?
  • PostgreSQLの自衛手段が動作するために,VACUUM FREEZEをきちんと行う様にしておくのがベター。

質疑やフリートークで出た話。

  • 論理削除について
    • トリガは多用すると、コストが高かったり、全容を隠蔽してしまう可能性もあるので、ここぞというポイントで利用するのがベターかも。
    • トリガを使ったときのテストには、PG_TAPみたいな応用出来そうなツールもある
    • 削除テーブル方式は、元テーブルのレコード件数も少なく保っておけるので、(生きているデータを相手にするデータアクセスには)より良いかも。
    • 削除テーブルの実現には継承、パフォーマンスの悪化にはWAL無しテーブル(9.1から)っていう方向性もあるよね!
    • 最近はORMで論理削除をサポートしようとする動きも若干ある。(そもそも論理削除は日本ではニーズが高いけど、諸外国はそうでもないらしい)
  • その他
    • みんなデータベースのmigrationってどうやってるんだろう?→ツールやサポートを行うORMが幾つかあるものの、大規模な変更時の物も含めてベターな手段はなかなか難しい模様。
    • Macユーザー多いですね!(林檎マークの背面パネルで埋め尽くされた机を見ながら)
    • 次回は10月頃?

感想

論理削除について。私もプロジェクトのデータベースで論理削除を使っているんですが、削除フラグを伝播しなくても良かったり、矛盾が発生するような要求が(まだ)無いので、比較的救われてるんだなと実感しました。
ただ「削除はされてないけど基本的には不要になったデータ」はどうしても出てしまうわけで、紹介していただいた手法はそういったデータにも使えそう。特に「削除フラグはbool値じゃなくてキー値が負数でも良いよね」っていう考え方は、普段エラーコードなどを使っていながら、目から鱗でした。大変勉強になりました。

周回問題について。PostgreSQLについて検索したときに単語は良く見かけていて、漠然と怖いなーと思っていたんですが、どういう仕組みなのか、現在のPostgreSQLがどういった対策をとっているのかを学べて一歩理解が深まりました。「運用で役に立つかどうかは別として」みたいな前置きもされていましたが、Xidの様な仕組みはアルゴリズム的な視点からも非常に興味深かったです。

時間が押していたので自重してしまったんですが、実は聞いてみたかった(リクエストしたかった)ネタとして、PostgreSQLには、複数のデータベースから固有のテーブルだけをレプリケーションする仕組みってあるのでしょうか。
例えば,Aデータベースからはfooテーブル、Bデータベースからはbar, bazテーブルだけをレプリケーションするCデータベースといった感じのものは実現できるのかなあと。やっぱり同期ツール的なプログラムをアプリケーション側で書くしか無いのでしょうか。