ぱと隊長日誌

ブログ運用もエンジニアとしての生き方も模索中

DB Online Day 2018 Summer「日本のデータベーススペシャリストは最終的にどこを目指すべきか?」聴講メモ

セッションについて

DB Online Day 2018 Summer (DB Online Day 2018 Summer)
基調講演  日本のデータベーススペシャリストは最終的にどこを目指すべきか?
の聴講メモです。

講演者は 関 俊洋 さん [株式会社アシスト] です。

自分のメモをベースにまとめています。発言の聞き間違い、解釈違いの可能性があることをご了承ください。

【参考】としている個所は私が挿入しています(補足や参考資料など)。講演者の講演内容ではありませんので、その旨ご了承ください。
資料の公開予定がないということでしたので、当日のスライドに表示されたものと同じような情報を探して紹介しています。

はじめに

スペシャリストというより、データベース(以下、DB)に携わっているという立場の方が多いと思われるため、タイトルを変更し「エンジニアがどこを目指すべきか」とした。
【参考】
当日の発表ではタイトルを変更されていました。その説明となります。

DBエンジニアの明確な定義はない。そこで、この講演では少しでもDBに携わっている方をDBエンジニアと定義する。

市場環境、技術トレンド、収入と働き方の3つについて話す。

市場環境について

人口ピラミッド。2030年には人口の1/3が65歳以上となる。
【参考】
f:id:pato_taityo:20180801214516p:plain
出典:国立社会保障・人口問題研究所ホームページ (http://www.ipss.go.jp/

IT人材不足は年々悪化し、人材供給は2019年をピークに減少する。
【参考】

マクロな規模でのIT人材(IT企業及びユーザ企業情報システム部門に所属する人材)は、現在の人材数は約90万人、不足数は約17万人と推計された。今後2019年をピークに人材供給は減少傾向となり、より一層不足数が拡大する。

IT人材の最新動向と将来推計に関する調査結果を取りまとめました(METI/経済産業省)

IT予算は増加傾向にあり、2017年で3割が増加すると回答している。2018年も同じ傾向。
人はいないが予算は増え続けるという真逆の動きとなっている。
【参考】

2017年度(2017年4月~2018年3月)のIT予算は、前年度から「増額」とした企業の割合が34%と、前年調査における2016年度の値から大きく上昇して3割を超えました。一方、「減額」とした企業の割合は前年調査の結果からさらに下回り、2001年の調査開始以来で最も低い水準となりました。

2018年度(2018年4月~2019年3月)に向けた見通しでは、「増額予定」が「減額予定」を大きく上回る傾向と、減額を見込む企業の割合が一桁台という様相は2017年度と同様であり、総合的にはIT予算の増額傾向は継続する予想です。

国内IT投資動向調査報告書2018 | ITR

ディープラーニングやAI/機械学習への投資意欲は非常に強いが、NoSQL, RDBMSへの投資意欲も少なくない。
【参考】
以下のリンク先の資料を参照ください。
国内IT投資動向調査報告書2018 | ITR
<参考資料4> 製品/サービスに対する投資意欲(OS/ミドルウェア分野)

汎用RDBMSは堅調。オンプレミスのシステム更改があるため。
DBaaSは活性化。クラウド移行が続いている。
アプライアンスOracle製品によって成熟期にある。
DWHはIoT・ビッグデータ需要で高成長している。

AI、機械学習ビッグデータは何のために使うのか。マーケティングでいえばレコメンデーション。カスタマーサービスならチャットボット。これらを実現するためのデータはデータベースにある。

だが、データ基盤が整っていないと回答する企業が多い。整理されていなかったり、エンジニアが不足していたり。もちろん、一部の先進的な企業では進んでいるが、多くの企業ではこれからであり、そこにエンジニアの需要がある。

DBエンジニアはデータ基盤と活用の間にいる。データ基盤の仕事は大きく変わらないが、手を伸ばせば活用できる場がすぐそばにある。

技術的なトレンドで考えるDBエンジニア

OracleのExadataが2008年に登場した。ハードとDBが切り離せなくなったという点で大きな転換点となった。
そして今、Oracleがオートノマスというテーマでサービスを提供している。

データベースの選択肢が増えた。RDBMS、KVS、ドキュメント指向など。これらの特性を考えて使い分けられるエンジニアが求められている。

アプライアンスの利用拡大により、アシストのようなソフトウェア屋がハードウェア屋も兼ねることになった。これに伴い、ネットワークやプロジェクトマネジメントのスキルも求められるようになった。この傾向は今も続いている。

OSSの利用拡大により、企業の基幹システムにOSSが使われている。
これに伴い、ソース解読の知識、複数DBの使い分け、異種間DB移行、コミュニティ活動などが求められてきた。
複数DBの使い分けは段階的にできるところから移行するために必要となる。
コミュニティ活動は個人だけでなく企業としても進める必要がある。

ビッグデータ時代は Hadoop, NoSQL, クラウドの知識が求められた。

クラウド時代に DB が as a Service 化し、ハードウェアの運用保守から解放された。代わりに、会計知識、システムデザイン、セキュリティ、クラウド使い分け、クラウド間の移行知識が求められた。

時代が進むごとに求められる知識が増え続けている。

5年前から近い将来に半数近い仕事がなくなると予想されている。
また、Oracle CEOはDBAが数十万人規模で失業すると予想している。こちらの予想はDBAにセグメントを絞り込んでいることに注意。
【参考】
OracleのCEOが予言「数十万人のOracleデータベース管理者は失業する」:Oracle Database 18cは管理者不要……らしい - TechTargetジャパン 情報系システム
OracleのCEOが予言「数十万人のOracleデータベース管理者は失業する」』という見出しの記事で、該当の発言部分は記事をダウンロードしないと確認できません。記事を確認したところ、同様の記載がありました(記事の引用は避けます)。

DBAの仕事は現在カバーしている範囲が虫食いのようになくなるのではないか。例えば運用フェーズの仕事がなくなるだろう。だが、隙間は残る。
また、機械で代替できるとしても、それをすぐに導入できるかは個々の企業によって異なるはず。

業務知識とIT知識とビジネススキルは代えがたい価値となる。
若手エンジニアのチューニングは ADWC (Oracle Autonomous Data Warehouse Cloud Service) に負けるが、ベテランはまだ勝てる。今後は機械に大部分を任せつつ、コアな部分を人間がチューニングするようになるのでは。
【参考】
Oracle Autonomous Databaseの自動チューニング vs 人間による性能チューニング。どちらが高性能をたたき出せるか実際に比べてみた[PR] - Publickey
エンジニアとADWCとの勝負はPublickeyで日本オラクル提供のタイアップ記事として紹介されています。

DBエンジニアはこれまでのDBAの枠を越えていく必要がある。

収入と働き方

アシストの場合、中途採用はプレイヤーとして採用している。管理職や専門職としては採用していない。
プレイヤーは管理職と専門職の2つのキャリアパスを選べるようになった。
昔は階段式なキャリアパスだったが、いまは複線型で自由な選択が求められるようになってきた。

エンジニア単価はコンサルタントとアーキテクトが特に伸びている。プロジェクトマネジメントやDBスペシャリストもまあまあ。単なるDBエンジニアはあまり伸びていない。

DBエンジニアが成長するためには経験による育成が特に重用と考えている。

DBエンジニアが感じるであろう変化は以下の通り。

  • 市場の変革
  • 組織の変革
  • 技術の高度化

変化に捕らわれるにではなく、変化を捉える。
データ活用のニーズは10年前も10年後も変わらない。
データを扱う技術を持つことで、社内でも社外でも、そして経営層に対してもリーダーシップをとることができる。

Ask The Speaker

セッション後、関さんに質問してみました。

Q.
(アシストのような)ベンダーの立場として、業務知識を得るためにどのような工夫をしているのか?
A.
営業経由で情報を得たり、現場に常駐して習得してもらったりしている。ユーザー企業のエンジニアとは異なり、業務知識の習得は中々難しいところ。

Q.
商用ソフトは書籍等の情報が豊富にあるが、PostgreSQLのようなOSSの情報入手はどうしている?
A.
PostgreSQLであれば個人レベルではユーザー会に参加したり、企業としてはコンソーシアムに参加して他社事例を得たりしている。

所感

DBA が失業するとの Oracle CEO 発言が紹介されていましたが、現時点でこの発言はやや強気すぎる気がします。というのも、この後のセッションで以下の話が出ていたからです。

Oracleとしては自動化でDBエンジニアのタスクを半分程度に減らせると考えている。

DB Online Day 2018 Summer「データで見る、経験で語る、日本のデータベーススペシャリストのリアリティ」聴講メモ - ぱと隊長日誌

ただ、将来の進化を織り込むと、Oracle CEO の発言にも現実味を感じます。DBAだけでなく、全てのエンジニアが技術+αが求められるようになり、それが「DBAの枠を越えていく」ということではないでしょうか。

DB Online Day 2018 Summer「データで見る、経験で語る、日本のデータベーススペシャリストのリアリティ」聴講メモ

セッションについて

DB Online Day 2018 Summer (DB Online Day 2018 Summer)
スペシャルセッション データで見る、経験で語る、日本のデータベーススペシャリストのリアリティ
の聴講メモです。

本セッションはパネルディスカッション形式で行われました。
モデレーター:DB Onlineチーフキュレーター 谷川 耕一 さん
パネリスト:株式会社アシスト 関 俊洋 さん
パネリスト:日本オラクル株式会社 小田 圭二 さん

自分のメモをベースにまとめています。発言の聞き間違い、解釈違いの可能性があることをご了承ください。

テーマ1 3種のデータベースエンジニア

Oracleでは社内外(主に社外)のDBAのスキル調査を行っている。このデータの分析結果をお話ししたい。

DBAを3つに分類し、各役割を整理する。

開発側DBA SQLチューニング、インデックス設計、バグ調査。
運用側DBA キャパシティ管理、トラブル対応、バックアップリカバリ、SQLチューニング。
全体最適DBA 一部の会社で任命している。品質管理、障害の横展開、標準ガイド作成、レビュー、難易度の高いトラブル対応。

DBAにはインフラスキルも必要。これがないとスキルが伸びない。

経験とスキルは比例している。DBAとして一人前といえるレベルには5~10年ぐらいの経験が必要になる。3年目では若干足りないぐらい。

SQLチューニングは運用フェーズでのタスクと思われがちだが、本来は開発段階から意識すべき。少ないデータ量で性能テストして本番で火を噴くのが最悪パターン。

開発側にいるとDBAとしての幅広い経験ができない。運用側のスキルが伸び悩む。運用の経験が大事。
運用は比較的速くスキルが伸びる傾向にある。
品質管理チームは経験が少なくともスキルの高い傾向にある。チームメンバーの年齢層が高いので、比例してドキュメンテーション能力が高い。

情シスは経験年数を積んでも一人前レベルに達していない。
でも、SIerも同じ傾向。特に大手は手を動かせていない印象がある。

アーキテクトやコンサルはスキルが高い傾向にある。

ドキュメンテーションやコミュニケーションスキルはかなり重用。時には技術スキルより重用となる場面がある。
データからもドキュメンテーション・コミュニケーション・インフラのスキルを持つエンジニアは年収が高い傾向にある。

データベースはインフラを知っていると応用が利く。SQLチューニングだけではその分野に特化してしまう。チューニングを専門にしている会社ではスポットでプロジェクトに参画し、仕事を終えると抜けることが多い。

劣化した性能をチューニングして回復させたとしても、元を越えることはできない。その壁を越えるためにインフラスキルが必要となる。

テーマ2 DBエンジニアの専門性スキルをどう捉えれば良いのか

チューニングで大切なのは目標を設定すること。また、SQLチューニング以外の手段も含め提案できること。

チューニングは今後もなくならない領域。自動化できる領域は増えるが、匠の領域がある。匠の領域では中身を理解している必要がある。

インスタンスチューニングで求められることの一つがメモリー関連パラメーターのチューニング。これには自動化・ユーザー数・セッション数・ロック等が関連してくる。これらの問題を解決することがインフラエンジニアとして求められる。

開発側が提示するパラメーター設定資料にはしばしばパラメーターの設定理由が書いていない。設定の見直しにあたっては根拠をもって見直す事が大切。

Exadataにはベストプラクティスがあるが、既存からのリプレースだと、過去のパラメーターを変えることに難色を示されてしまうことがある。

アシストの実感として、テーブル設計をできるエンジニアは減ってきている。データモデルを考えることのできるメンバーがベテラン層に寄ってきている。
データベースエンジニアと呼ばれる人はシステムが使われる業務の現場から離れていることが多い。
モデラーと呼ばれる人は変わった人が良い。何人か集まればみんな違った持論を展開する。

バックアップを設定したことはあっても、実際にリカバリーしたことのない方が多い。事前に検証環境でもいいからやっておくべき。そうでないと、現場でヒリヒリした思いをすることになる。
データベースの内部構造を知らないと、障害の発生している現場での疑問に答えることができない。これは場数を踏んで経験を積むしかない。

トラブル時は例外的な壊れ方をすることが多い。これはツールで救えないこともしばしばある。

英語は使わないと覚えない。まずはドキュメントを読む。下手でも良いからしゃべる。IT人材不足の話が出たが、人が減れば外国のエンジニアとの協業が必要になる。そこで英語が必要となるはず。
Oracleに関しては日本語ドキュメントがある程度そろっているが、クラウド系だと英語ドキュメントを参照する必要がある。
英語ドキュメントはGoogle翻訳でも良いから読んでみる。翻訳を待っていると時間がかかりすぎる。
Oracle内部では未だに現地の言葉に翻訳しているのは日本ぐらいと言われている。

テーマ3 DBエンジニアのスキルアップにどうアプローチする?

キャリアのスタートがインフラか開発かでデータベースへの見方が決定的に違う。開発から始めたエンジニアはデータベースを単なるデータの入れ物とみていることが多い。開発エンジニアもインフラ視点で見ると気づきがあるはず。

開発側も経験することのメリットにアルゴリズムの理解が早くなることが挙げられる。

運用側から入ったエンジニアはインフラ全般、特にトラブル対応のスキルが伸びやすい。一方、安定稼働してトラブル対応が減った現場ではエンジニアのスキルが伸び悩むこともある。

トラブルが起こった現場に行くと、ステークホルダーの関係性や業務影響のインパクトを肌で感じられる。

クラウド時代にネットワークのスキルは大切だが、全てのスキルを満点にする必要はない。得意分野を持ち、苦手分野は任せるかお金で買えば良い。お金で時間を買う。データベースエンジニアとしてはデータベースを中心に、ネットワーク、ストレージのような他の2,3スキルを掛け算する。

どれだけAIが進化しても、お客様とビジネスを一緒に考える仕事はなくならない。

データ活用はそんなに簡単じゃない。データはあっても定義がなかったりする。

アシストではデータベースの活用はほかの部署と分けている。それぐらい難しいし、専門的スキルが必要になる。

ユーザーのリクエストに応えて正しいデータを提供できているのは半分以下という報告もある。

分析の時間は5%以下。それ以外の大部分の時間はデータクレンジングに使われている。

テーマ4 クラウドになるとDBエンジニアはどうかわるのか

Oracleクラウドはバックアップの自動化ができる。細かい設定はできないが、難しいバックアップ設計を任せることができる。

Oracleはオートノマスで自動的にチューニングする。そのため、デフォルトではインデックス作成すらできない(エラーになる)。

OracleでDBエンジニアのタスクを整理したところ、120ぐらいあった。だから、何を自動化に任せ、何を尖ってスキルとして身につけるかを考えていく必要がある。Oracleとしては自動化でDBエンジニアのタスクを半分程度に減らせると考えている。ただし、現場によって状況は変わる事に注意。

ベンダーやSIerとしてはオートノマスで食い扶持が減ると感じるかもしれないが、工数が減ることで期日を守りやすくなることをメリットとして捉えることもできるはず。
例えばバックアップの自動化にはOracleのベストプラクティスが適用されている。都度設計しなくて済むことは大きい。

日本のミッションクリティカルなシステムにはIaaSがあっている。リフト&シフトのやり方。だが、PaaSにしていかないと構築や運用タスクが減らない。IaaSで始め、PaaSに進めていくのが良いのでは。

クラウド化してもチューニングの要素はなくならない。SQLチューニングだけでなく、スケールアップやキャッシュなどのクラウドならではのテクニックが使える。
クラウドによってパケットキャプチャでの解析が改めて重要になってくる場面も出てきている。

アシストではExadataの価格を自社サイトで公開しており、このページへのアクセス数が多い。価格に興味を持つ方が多いということ。クラウドサービスでも価格情報がオープンになっている。ユーザー自らコストを踏まえて判断・提案するようになってきたし、エンジニア側もコストについて理解していないといけない。

Ask The Speaker

セッション後、登壇者のお二人に質問してみました。

Q.
セッション中に技術分野を深堀するという話が出たが、どこまで深堀して進むべきか?どこであきらめるか?

A.
人によって壁に突き当たるところがある。そこまで進めて、一旦他の事へ進め、また必要になったり壁を乗り越えられるようになったら進む。(小田さん)
マネージャーとしては会社の方向性と個人の方向性にギャップがあるとき、個人のやりたいことを伸ばしてやり、マネージャーがそのギャップを埋める。マネージャーは忙しくなるが…。(関さん)

所感

今回のセッションを通し、知識と経験は両輪であり、どちらも必要なことであると改めて感じました。
例えば、パフォーマンスチューニングを解説した資料は数多くありますが、現場でそれを適用しても思ったような効果を得ることは難しいと感じています。ですが、そうした知識が無駄なわけではありません。なぜそれがうまくいかないかを考え、別の方法を考え付くためにさらに幅広い知識が必要となります。そして、そこでの経験が次回のチューニング作業を効率化してくれます。

自動化が進めば半端な知識や経験では太刀打ちできなくなるでしょう。そんな状況下でもエンジニアとしての価値を出すためには日々の研鑽あるのみ、ということではないでしょうか。

PostgreSQLのシリアライザブルとコミット/ロールバックと遅延可能な読み取り専用トランザクションの関係

はじめに

PostgreSQLトランザクション分離レベルにはシリアライザブル(Serializable)があります。ドキュメントのシリアライザブル分離レベルの説明には以下の記載があります。

異常を防止するためにシリアライザブルトランザクションを使用するのであれば、恒久的なユーザテーブルから読み取られたいかなるデータも、それを読んだトランザクションがコミットされるまで有効とは認められない点は重要です。 このことは読み取り専用トランザクションにも当てはまりますが、遅延可能な読み取り専用トランザクション内で読み込まれたデータは例外で、読み込まれてすぐに有効とみなされます。 なぜなら、遅延可能なトランザクションはすべてのデータを読み込む前にこのような問題がないことを保証されているスナップショットを取得できるまで待機するからです。 それ以外の全ての場合において、後に中止されたトランザクション内で読み込まれた結果をアプリケーションは信用してはならず、アプリケーションはトランザクションが成功するまで再試行すべきです。

13.2. トランザクションの分離

この説明を実例で確認し、トランザクション設計で注意すべきポイントを探ります。

検証環境・シナリオ

PostgreSQL 10.3 で検証を行いました。

PostgreSQLに Serializable Snapshot Isolation (SSI) が実装されたのは 9.1 からです。よって、9.1 以降であればほぼ同様の結果が得られると思われます。

検証SQL(データ含む)は PostgreSQL wiki の SSI 解説記事(以下、記事)を参照しました。
SSI - PostgreSQL wiki
2.4.1 Deposit Report を参照ください。

記事に従い、postgresql.confのパラメータを以下の設定とします。

default_transaction_isolation = 'serializable'

初期セットアップとして、以下のSQLを実行します。

create table control
  (
    deposit_no int not null
  );
insert into control values (1);
create table receipt
  (
    receipt_no serial primary key,
    deposit_no int not null,
    payee text not null,
    amount money not null
  );
insert into receipt
  (deposit_no, payee, amount)
  values ((select deposit_no from control), 'Crosby', '100');
insert into receipt
  (deposit_no, payee, amount)
  values ((select deposit_no from control), 'Stills', '200');
insert into receipt
  (deposit_no, payee, amount)
  values ((select deposit_no from control), 'Nash', '300');

検証環境のロケールによっては金額表示に円記号"¥"が用いられますが、ここでは記事に沿ってドル記号"$"で表記しています。

検証シナリオ概説

銀行の預金管理を想定しています。(もしかすると、記事では小切手を想定しているかもしれないのですが、シナリオの本質には影響しないので、本エントリでは預金の想定で進めます)。

control テーブルと receipt テーブルがあります。

◆ control テーブル

列名 説明
deposit_no 預金番号。日次バッチ処理の単位となり、締め処理が行われるとインクリメントされ、翌営業日扱いとなります。

◆ receipt テーブル

列名 説明
receipt_no 受領番号。シリアルな値です。
deposit_no 預金番号。control テーブルの deposit_no を参照します。
payee 預金者。
amount 預金額。

シナリオでは以下の3つのトランザクションがほぼ同時に起こります。

トランザクション 説明
T1 預金の預け入れ。
T2 預金の預け入れの締め処理。続けてT3の処理を行う。
T3 T2で締めた預け入れ分の預金の一覧出力。

この時、それぞれのトランザクションがどのように扱われるかを確認します。

実験結果・解説

T1完了前にT2, T3が進行する

記事のオリジナルのケースです。
当日の預金の預け入れ処理(T1)が完了する前に締め処理(T2, T3)が進行します。

BEGIN; -- T1

INSERT INTO receipt
  (deposit_no, payee, amount)
  VALUES
  (
    (SELECT deposit_no FROM control),
    'Young', '100'
  );

SELECT * FROM receipt;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
4 1 Young $100.00
BEGIN; -- T2

SELECT deposit_no FROM control;
deposit_no
1
-- T2

UPDATE control SET deposit_no = 2;

COMMIT; -- コミット処理が成功する。
BEGIN; -- T3

SELECT * FROM receipt WHERE deposit_no = 1;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
-- T1

COMMIT;

ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.
-- T3

COMMIT; -- コミット処理が成功する。

トランザクション間に T1 ⇒ T2 ⇒ T3 ⇒ T1 という順序関係が発生したため、シリアライズすることができず、T1 のコミットに失敗しました。

トランザクションの順序関係に矛盾が生じていることは、T1とT3のSELECT結果が異なることからわかります。 T1 ⇒ T3 が成り立つのであれば、T3にはT1のINSERTが反映されているはずですが、実際には反映されていません。

T2とT3の間にT1がコミットする

オリジナルではT3の SELECT 実行後にT1がコミットを実行(そして失敗)していましたが、T1のコミットがT3の前であればどうであったかを確認します。

BEGIN; -- T1

INSERT INTO receipt
  (deposit_no, payee, amount)
  VALUES
  (
    (SELECT deposit_no FROM control),
    'Young', '100'
  );

SELECT * FROM receipt;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
4 1 Young $100.00
BEGIN; -- T2

SELECT deposit_no FROM control;
deposit_no
1
-- T2

UPDATE control SET deposit_no = 2;

COMMIT; -- コミット処理が成功する。
-- T1

COMMIT; -- コミット処理が成功する。
BEGIN;  -- T3

SELECT * FROM receipt WHERE deposit_no = 1;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
4 1 Young $100.00
-- T3

COMMIT; -- コミット処理が成功する。

トランザクションを T1 ⇒ T2 ⇒ T3 という順序関係で解決することができるため、いずれもコミット処理が成功しました。

T1のコミット前にT3がコミットする

オリジナルではT3のコミットが一番最後でしたが、もしT1のコミット前にT3がコミットしたらどうなるかを確認します。

BEGIN; -- T1

INSERT INTO receipt
  (deposit_no, payee, amount)
  VALUES
  (
    (SELECT deposit_no FROM control),
    'Young', '100'
  );

SELECT * FROM receipt;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
4 1 Young $100.00
BEGIN; -- T2

SELECT deposit_no FROM control;
deposit_no
1
-- T2

UPDATE control SET deposit_no = 2;

COMMIT; -- コミット処理が成功する。
BEGIN;  -- T3

SELECT * FROM receipt WHERE deposit_no = 1;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
-- T3

COMMIT; -- コミット処理が成功する。
-- T1

COMMIT;

ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.

T3のコミット処理は成功し、T1のコミット処理を失敗させることで、T2 ⇒ T3 となりました。T3のコミット処理を失敗させて、T1のコミット処理を成功させることで、T1 ⇒ T2 にすることもできたはずですが、そうなりませんでした。

T1のコミット前にT3がロールバックする

前の例ではT1のコミット前にT3がコミットすることで、T1のコミットが失敗しました。ではT3がロールバックすればT3はなかったことになり、T1のコミットは成功するのでしょうか?

BEGIN; -- T1

INSERT INTO receipt
  (deposit_no, payee, amount)
  VALUES
  (
    (SELECT deposit_no FROM control),
    'Young', '100'
  );

SELECT * FROM receipt;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
4 1 Young $100.00
BEGIN; -- T2

SELECT deposit_no FROM control;
deposit_no
1
-- T2

UPDATE control SET deposit_no = 2;

COMMIT; -- コミット処理が成功する。
BEGIN;  -- T3

SELECT * FROM receipt WHERE deposit_no = 1;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
-- T3

ROLLBACK; -- ロールバック処理が成功する。
-- T1

COMMIT;

ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.

T3がロールバックした後にT1がコミットしても、T1のコミットは結局失敗しました。不思議に思えますが、全体でみればT2のみ実行されたことになり、シリアライズは成立しています。推測となりますが、このケースで本来は成功してもよいT1のコミットが失敗するのは PostgreSQL の SSI の設計もしくは実装上の制約と思われます。

T3を遅延可能な読み取り専用トランザクションで実行する

処理時間が長く、途中での失敗を避けたい処理(例:締め処理)であれば、「遅延可能な読み取り専用トランザクション」内で実行することが一つの手法となります。
マニュアルから該当の記述を引用します。

DEFERRABLEトランザクション属性は、トランザクションがSERIALIZABLEかつREAD ONLYである場合のみ効果があります。 あるトランザクションでこれら3つの属性がすべて選択されている場合、最初にスナップショットを獲得する時にブロックされる可能性があります。 その後、そのトランザクションをSERIALIZABLEトランザクションの通常のオーバーヘッドを伴わず、またシリアライズ処理の失敗を引き起こす恐れやシリアライズ処理の失敗によりキャンセルされる恐れもなく実行することができます。 これは時間がかかるレポート処理やバックアップによく適しています。

SET TRANSACTION
BEGIN; -- T1

INSERT INTO receipt
  (deposit_no, payee, amount)
  VALUES
  (
    (SELECT deposit_no FROM control),
    'Young', '100'
  );

SELECT * FROM receipt;
receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
4 1 Young $100.00
BEGIN; -- T2

SELECT deposit_no FROM control;
deposit_no
1
-- T2

UPDATE control SET deposit_no = 2;

COMMIT; -- コミット処理が成功する。
BEGIN;  -- T3

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY, DEFERRABLE; -- 遅延可能な読み取り専用トランザクション

SELECT * FROM receipt WHERE deposit_no = 1;
-- レスポンスが保留される。
-- T1

COMMIT; -- コミット処理が成功する。

ここでT3のレスポンスが返ってきます。

receipt_no deposit_no payee amount
1 1 Crosby $100.00
2 1 Stills $200.00
3 1 Nash $300.00
4 1 Young $100.00
-- T3

COMMIT; -- コミット処理が成功する。

T3のSELECTのレスポンスがT1のコミット処理を待ち合わせたことで、T1 ⇒ T2 ⇒ T3 の順序関係となり、全てのトランザクションが成功しました。

まとめ

リアライザブル分離レベルではトランザクションシリアライズに実行されることを保証しています。ただ、PostgreSQLがその保証を満たすためにどのトランザクションを失敗させるかを事前に知ることは困難です。また、トランザクションロールバックしても、後続の処理に影響を与える場合があります。実行する処理の特性をふまえ、遅延可能な読み取り専用トランザクションで実行するなどの対応が必要です。