RDBはACIDだからって本当に安心して良いのか?
「この番組は「エンジニアの成長は楽しい、学びから」をモットーに、昨日より少し成長できる学びをわいわいお届けするエンタメ系テックラジオです」
「よっこいしょー」
「はい、というわけで今日はですね」
「はい」
「「データ思考アプリケーションデザイン」という書籍の第七章、トランザクションという章からですね」
「おおー」
「えー、一部を取ってきて」
「はい」

「アシッドの弱点」
「弱点?」
「アシッドの穴?」
「アシッドの穴?」
「お」
「うん」
「はい。についてちょっとお話ししていこうかなと思います」
「なるほど。てっきり分離レベルとかが来るのかと思った」

「あー、いや、似たような話ですよ」
「似たような話なんだ」
「はい、似たような話ですよ」
「そうなんだ」
「はい。でーね、ほんとはね、ちょっとね、順平に問題出しながらやりたかったところなんですけど」
「はい」
「えー、ちょっと探りながらいきますね」
「お、はい」

「Eコマースのサイトまず思い浮かべていただいて」
「はいはいはい」
「で、まあなんか購入しますと」
「うん」
「で、購入する処理をやるときに、えー、なんか在庫を1つ減らすような処理をすると思います」
「うん」
「えー、データベースを直接叩く場所」
「はい」

「アプリケーションで言うと、もうSQL直叩きするというふうなことを想像したときに」
「うん」
「なんかどんなコードにするでしょうかというところで」
「ん?」
「普通に購入するから在庫を1個減らすっていう処理」
「はい」
「SQLでどう書くかなというところで」
「うん」

「ちょっと1個じゃあ例を出してみましょうか」
「はい」
「本当に多分無難に、もう何も考えずに書くとですね」
「うん」
「多分セレクト文で在庫を見ますと」
「見ました」
「で、取得した数が」
「うん」

「えー、注文数より」
「うん」
「多かったら」
「うん」
「えー、アップデートとかで」
「うん」
「在庫数を減らしますと」
「注文、ああはい。在庫のほうが多かったらってことですね?」

「はい」
「うん」
「そうです、在庫のほうが多かったら。在庫のほうが少なかったらエラー出して終わりますと」
「はい」
「はい。今コード思い浮かべましたかね?」
「思い浮かべました」
「はい。ま、こういう書き方をしてるアプリケーション、全然世の中いっぱいあるかなと思うんですけど」
「はい」

「絶対こんなことしちゃだめです」
「わかりました」
「はい。絶対だめです」
「わかりました」
「で、なんで絶対だめなのかということを」
「うん」
「今日の話聞くと。理解することができると。で、あとどうしたらいいかがわかると」
「はい」

「えーいう話になります」
「なるほど」
「えー、じゃあまず最初ですね」
「はい」
「さっき言ったこのセレクトして、で、数どうかなって見て、アップデートかける」
「うん」
「これ何がいけないんだというところなんですけど」
「はい。いいじゃないですか、個数足りてるんだから」

「本当ですよね」
「はい」
「これがですね、えー、まあEコマースのサイトとかだとね」
「うん」
「ただなんだろうね、えー、Amazonプライムセールとかがあったとしましょう」
「はい」
「めっちゃ注文来ますと」
「うん」

「めっちゃ注文来るとですね」
「うん」
「この、ま、セレクト、読み込んで判断して書き直す」
「うん」
「っていうこの3ステップが平行に走りますと。平行に走る可能性があります」
「平行に、だからAさんBさんのが両方同時に走るよっていうことですか」
「そうですね」
「うん」

「かいちが読み込んで」
「うん」
「で、判断、あー在庫いっぱいあるわ。で、減らすって書き込みをする前にのりさんが読み込んで」
「うん」
「のりさんのほうもOK出て」
「うん」
「で、のりさんと僕で在庫10個しかないのに」
「うん」

「8個ずつ買うみたいな」
「なるほど」
「そんな処理が起きてしまいます」
「はい」
「で、これ恐ろしいのがですね」
「はい」
「テストじゃわかんないんですよ」
「あー、確かに」

「ソフトウェアテストでこれをテストするときって」
「うん」
「多分在庫が、いやちょっとデータベースモックにする気がするんですけど、まあ例えばE2Eだとして」
「うんうんうん」
「えー、データが、まあ在庫が10個あって、5個購入したら残り5個になるみたいな」
「うん」
「ま、テストを書くわけですよ」
「はい」

「これは成功します」
「しますね」
「C」
「はい」
「今回この平行で実行したときバグるよねみたいな、そんなテスト書かないっす」
「確かに」
「はい。それゆえ」
「はい」

「まあ実装されうるし。これなんならAIは平気で実装してくると思います」
「マジっすか」
「はい、注意しないと」
「うんうんうん」
「で、このテストの、テストじゃないや、すいません。この書籍の中で」
「はい」
「このバグですね」
「うん」

「実際に世の中にある」
「うん」
「あー、世の中のアプリでいっぱいあるぞっていう話をしてて」
「うんうん」
「えー、まあEコマースのサイトとかでも、まあこれちょっといろいろぼかされてたんですけど、まあ人気ECサイト12個で、えー、この平行したときに在庫以上のものを買えるような攻撃が成立したとか」
「うんうんうん」
「あとは2014年にあるビットコインの取引所の出金リクエスト」
「うん」

「の同時多重送信でビットコインを通常よりも盗まれ、盗むことができてしまったと」
「うーん」
「ま、結構大事件なんですけど、これも」
「確かに」
「はい。このさっきのSQL、セレクトして、えー、条件確認してアップデートするっていうふうな書き方をすると」
「うん」
「こういうやべえことが起きますと」
「うんうんうん」

「なので、まあかなり注意する必要があるんですね」
「うん」
「で、まあ正直、その僕もなんでしょうね、めちゃくちゃリクエストが来る、スパイクでめっちゃリクエストが来るようなアプリケーションってあんまり開発したことがなくて」
「うんうんうん」
「ま、幸いそんなにこういう被害を、被害というかなんだ、なんかやらかしをしたことはないんですけど」
「はい」
「おそらくこういうスパイク的にリクエストが来るようなアプリケーションにおいて、このデータベースの触り方っていうのは非常に注意する必要が」
「うん」

「あるんですね。で、ここまででなんかちょっと無難に実装するとやべえぞっていうところをちょっとお話ししたんですけども」
「はい」
「えー、ここから、まあアシッドってなんだっけというところ」
「うん」
「なんだっけというのと、あとは穴があるって言ったのってなんだっけというところをちょっとお話に移っていきます」
「はい」
「えー、リレーショナルデータベースにはアシッドの特性が、性質があるよっていうふうに、まあ言われるんですけど」
「うん」

「えー、これがですね、A、アトミシティ、原始性」
「うんうん」
「これは、まあなんかなんて言うんでしょうね、えー、中途半端な処理で終わらないよっていうんですか。ま、全部変更が終わるか、何も変更されないかというような」
「全か無かの法則ってことですか」
「そうですね」
「うん」
「全か無かの法則、うん。がA。で、Cはデータが正しい状態を保ち続けることができるという一貫性」
「コンシステンシー?」

「コンシステンシー。Iはアイソレーション。同時実行でも干渉しないよ」
「うん」
「っていう。分離されてるよっていう分離性。Dがデュラレビリティ、D。デュラ、デュラビリティ、えー、永続性。コミットしたら消えないよ」
「うん」
「というものが、まあアシッドと呼ばれる性質になります」
「はい」
「えー、ただですね、このデータ思考アプリケーションデザインの中では、このアシッド特性」
「うん」

「別にそんなないよって言ってます」
「別にそんなないの?」
「はい」
「ちょっとそれは結構天地ひっくり返るレベルの新事実なんですけど」
「で、え、ただなんて言うんでしょうね、これで別にそんなないよって言ってんのは、まあちょっと一部ほんとにないんですけど」
「うん」
「ま、大体データベース単体というよりはアプリケーションってデータベースだけで成立してるものではないので」
「うんうんうん」

「本当にアプリケーションデザインの文脈で言うと、えー、RDB使ったとてアシッドは別に保証されるものじゃないよということを言ってるんですけど、ちょっと詳しく見ていきます」
「え、えっとすいません、それは機能はあるけど使わなきゃそれは動かないよってそういう意味でもない?」
「でもない」
「でもない?」
「でもない」
「なるほど」
「ま、一部そう。一部そうなんですけど、そうでもないです。はい」
「じゃあちょっと続きをお願いします」

「続きいきます」
「はい」
「で、えー、まあAからいくんですけど、Aは、まあある程度ある。原始性はある程度ありますと」
「うん。あ、そっか、1個ずつにあるないがあんの?」
「あ、そうです」
「ああ、なるほど」
「はい」
「まず原始性はある」

「ある」
「つまり、えーっと、中途半端に成功することはないと」
「えー、ない」
「うん」
「うーん、いや、あー、うーん、あー」
「え?」
「え?あー、なんて言えばいいんだろう」
「これちょっとご質問いいですか」

「はい」
「この中途半端っていうのは、例えばトランザクションで、えー、データベース更新する処理が例えば3つぐらい並んでたとして」
「はい」
「それが、えー、基本的には、えー、1個も成功しないか3つ成功するかのどっちかですよっていう認識でまず合ってます?」
「えー、アシッド性、アシッドの中のAの」
「はい」
「概念というか定義としてはそれで合ってます」
「うんうんうん」

「ん、うん。で、この書籍の中では」
「はい」
「そこまでではないと言ってると思います」
「そこまでではない」
「なんかその、なんでしょうね、複数のテーブルにまたがった修正があったりとか」
「うん」
「で、あとはそのアプリケーションの中で」
「うんうん」

「本当に保証したい原始性」
「うん」
「はすべて、えー、保証できないって言うんですか、なんて言えばいいんでしょうね、えーっと、1回で1つのテーブルの1レコードに関しては原始性あると思うんですよ」
「うん」
「本当に中途半端に書き込まれたものとかはない」
「はい」
「けど、1個の処理の中で、なんか複数回データベースに書き込みをしたりとかする場合に関しては」
「うん」

「アプリケーション側でどうにかしないと中途半端なものができる可能性はある」
「ああ」
「ですね」
「なるほど」
「はい。ま、なのでデータベース自体には原始性はあるんですけど」
「うん」
「なんかアプリケーションデザインとしては、ま、ちょっと注意は必要ではあるし」
「うん」

「あとはDB外の副作用とかも、まああると思うので」
「うん」
「例えばさっきのEコマースの購入で言うと、なんか買ったら、まあAmazonとかだと購入しましたよメール来るじゃないですか」
「はい」
「で、あれもまあ副作用の1つですね、メール送信」
「うんうんうん」
「ま、この辺は中断できないので、中断じゃないや、えーっと、やり直せないというか」
「はい」

「メール送られたけどアプリの画面上は失敗って出てるみたいなのはあり得ると思うんで」
「うんうんうん」
「その辺はあの処理順とかを気にしながら、原始性を、データベースの原始性を生かせるように設計する必要がありますね」
「うん」
「ま、なんでデータベースに書き込む前にメール送ったりしないってことですね」
「なるほどね。一旦コミットされてから送れよっていう」
「あ、そうですそうです」
「うん」

「はい」
「うん」
「まあAはまあ置いといて」
「うん」
「まあある程度あるんで」
「ある程度」
「まあほぼある」
「はい、ほぼある」

「ほ、ほぼある」
「Aはほぼある」
「はい。続いてC」
「はい」
「Cは、まあ一部あるんですけど。すべて、えー、DBの責任ではないと言ってます」
「ん?」
「Cはあの」
「一貫性?」

「えー、はい、一貫性ですね。このデータが、なんだろうな、その、データ固有のルールを守り続けるかみたいなところなんですけど。なんか例えば」
「はい」
「なんかユニーク制約とかってDBで設定できるじゃないですか」
「はいはいはい」
「あの辺はDBがやれるんですよ」
「うん」
「一方でなんかドメイン知識的な感じで」
「うん」

「えー、そうだな。例えばじゃあ銀行口座で言うと」
「はい」
「のりさんと僕がそれぞれ口座を持っていて」
「はい」
「えー、僕からのりさんに1万円送るとします」
「うん」
「で、そのとき僕からのりさんに1万円送ったあとの」
「うん」

「のりさんと僕の口座残高の合計って合ってるはずじゃないですか」
「そうっすね」
「ただ、その、のりさんと僕の口座残高が合ってることはDBは保証してくれないです」
「ほー。えーと、それは検証できないっていう意味で?」
「DBのエンジンが」
「うん」
「ここが合ってないから処理失敗っていうふうにはできない」
「あー、チェック制約的なものが働いてないよってこと?」

「はい」
「うんうんうん」
「ま、もちろんね、その数字がマイナスにならないみたいなのはすごい大事で、これはDBでできるんですけど」
「うん」
「なのでさっきのEコマースで言う、僕とのりさんが過剰にものを買ったときに」
「うん」
「エラーにするっていうところで言うとDBもやれるんですけど」
「うんうん」

「えー、DBのそのデータ型とかで、ま、定義しきれないような」
「うん」
「なんか細かーい制約みたいなところについては」
「うんうん」
「アプリ側で、えー、正しく検証するように書いて」
「うん」
「やらないと、このCっていうのは守りきれないよねっていうふうなことを言ってました」
「あー。なんか、ゆうちょの番号とかさ、決まったルールあるじゃないですか、なんか」

「はい。えー、こ、口座番号っすか?」
「はい」
「はい」
「そういうのってデータベースでチェックできないよねみたいな、なんか、な、なんて言うんだろうな、プログラム的なチェックができないってことなのかな?」
「あー、はい。それも1つですね。そうですね」
「チェックサムみたいな」
「適当な言葉をつけれないみたいな、はい」
「ん、でもそれって一貫性なのか?」

「はい。アプリケーションレイヤーで言うと」
「うん」
「その、常に真であるべきルール」
「うんうんうん」
「っていう意味では一貫性であると理解しています」
「なるほど」
「本当にだからなんて言うんでしょうね、データベースができる範囲でのCはあるんですけど」
「うんうん」

「アプリケーションに求められるCをすべてDBに押し付けることはできない」
「うん。うんうんうん」
「っていう感じですね」
「なるほど」
「で、ちょっとAとC来て、次Iなんですけど」
「はい」
「Iが1番重いんで、一旦Dに行くんですが」
「一旦、はい」

「はい。D、これ永続性ですね」
「うん」
「これも言うてね、障害起きたらデータ吹っ飛びますよということを言ってます」
「あー。まあ。まあまあまあ、確かに」
「まあまあまあっていう」
「え、これどの規模のことまで言ってんだろうね」
「えーっと」
「例えばさ」

「停電とか」
「例えば地球が爆発してなくなったらなくなりますよねみたいな、なんか、そんなヘリ、ヘリクスみたいなこと言ってるのかな」
「えっと、例えば、なんかSSDとかだと、あのー、ほんとに内部電源も全部吹っ飛ぶと」
「うん」
「もうデータが化けちゃうらしいんですよ」
「うーん」
「とか、あとは過電流とかが流れると、ま、ハードディスクとか故障しますし」
「はい」

「っていう、なんかハードウェア故障の話をしてますね」
「うーん」
「ま、なのでアプリケーションデザインっていうレイヤーでは、ま、適切に、なんかレプリケーションとかバックアップとか」
「うん」
「っていうのをちゃんとやりましょうねっていうのを書いてます」
「なるほど。だから、まあそれも機能単体で及ばないところは、えー、アーキテクチャを設計することによって、えー、守っていくべきところですよっていう」
「そうですね」
「そういうことですね」

「はい」
「うんうん」
「で、まあちょっと重いI」
「重いI」
「重いI。なんか」
「I、あ、重いIっていうとね、ちょっと」
「なんかちょっとメンヘラっぽい感じするけど」
「アイソレーションです」

「はい、アイソレーションね」
「はい」
「で、これアイソレーション何かというと、えー、並行のトランザクションが互いに干渉しないようにする、なってるよっていうのが、まあ分離性」
「うん」
「になっていて。で、さっきのその最初のEコマースの例で言ってた」
「うん」
「のりさんと僕が同時に書き込んだときに、過剰に在庫吐き出しちゃうことあるよねみたいな」
「うんうん」

「ところが、まあ分離性になるんですけど」
「うん」
「さっき言ったとおり、SQLのデフォルトの設定でさっきの書き方をすると、アイソレーションないんですよ」
「デフォルトの設定でやるとアイソレーションがない?」
「はい。なんかデータベースごとにアイソレーションレベルの設定ができるんですけど」
「はい」
「ただデフォルトで設定すると、さっきののりさんと僕の例のように」
「うん」

「過剰に在庫を吐き出すような設定になってしまいます」
「ほー。え、それトランザクションを使ってもってこと?」
「そうですね、はい。トランザクションを使っても。えーっと、トランザクションを使うと、すいません、どっからどこまでをトランザクションを使うって言ってます?」
「えー、スタートトランザクションからコミットまでの間」
「セレクトからってことですよね?」
「うん」
「はい。あ、それやると直列というか、アイソレーションができるんですけど」
「うん」

「それはそれでいいのかなっていうところがあります」
「やって、含みがすごいぞ、はい」
「ちょっとあとで話すんで」
「はい」
「ふわっとさせとくんですけど」
「わかりました」
「はい。あ、いや、そんなことないか」
「ん?」

「あ、し、ちょ、話しちゃいます」
「はい」
「早速」
「ああ、早速、はい」
「はい。さっきののりさんが言ってた、じゃあそのトランザクションに1つ、ま、ひとまとまりにしちゃうのどうなんのっていう」
「うん」
「ところなんですけど」
「うん」

「これあの、ほんとに、なんだ、真正面の直列実行」
「うん」
「っていう解決策になりますね」
「うんうん」
「で、これ、まあやろうと思うとどうなるかというと、さっきの例で言うと、えー、Eコマースのサイトで僕が購入ボタンを押しました」
「はい」
「で、セレクトを押します」
「うん」

「セレクトが実行されます」
「うん」
「で、そのタイミングで多分のりさんが購入してセレクトを実行しようとします」
「はい」
「ただ、えー、かいちのトランザクションが実行中なので」
「うん」
「のりさんのほうは待ちます」
「はい」

「で、かいちのやつが終わったあとに、のりさんの処理が始まって」
「うんうん」
「えー、処理がされて、あ、もう在庫ないよって言ってエラーが出るみたいな」
「うん」
「ま、そんな動きになると思いますけど」
「はい」
「ま、これも解決策の1つではあるんですが」
「うん」

「これってクエリの処理が重くなるんですね」
「そうっすね」
「トランザクション処理か、はい」
「待ちが長くなっちゃう」
「そうです。で、待ちが長くなると」
「うん」
「まあ、ほんとにユーザー数が多いようなサービスにおいては」
「うん」

「ま、タイムアウトが発生したりだとか、あとDBの負荷も上がんのかな、上がんねえか。DBの負荷上がんないと思うんですけど、パフォーマンスにちょっと問題が出てくる」
「うんうんうん」
「ですね。なので、まあサービスもスケールしないし、あとはなんか、それこそね、さっきは在庫10個しかないからブロックできて良かったなんですけど」
「うんうん」
「じゃあ在庫が1万個あって、えー、200人が殺到しますみたいな。そういう大セールな場合に、まああんまり、なんだろうな、ユーザーが熱狂してるうちに購入してくんないというか」
「うんうんうん」
「それはそれでちょっとビジネス的な課題がありそうだなとは、いうのがまあ順次実行の強みと弱みの部分になりますね」
「なるほどね。整合性は保てるけどもみたいな」

「そうです」
「うん」
「っていうので、じゃあそれをまあ解決しつつ別のトレードオフもあるよみたいなのがあと2つ手法としてあるんですけど」
「えー、ミスったら謝る」
「あー、1つ、それも」
「おお」
「ん?いや、ちょっと待ってください。ミスったら謝るってどういうことだ?」
「えーっと、整合性が崩壊したときに関係者各位に謝る」

「あ、違う違う違う違う」
「違う」
「違う違う違う。違います違います」
「ソフトスキル」
「えーっと、1個は多分当てれるかもしんないですけど」
「うん」
「1個は当てれる気がするんですけど、なんだと思います?」
「えー、結果整合性を保つようにする」

「それで在庫とかだと問題ないのか、ほんとに」
「在庫は問題ありそう」
「ですよね」
「待てよ、なんだ、出てくるぞ。いや、出てこないか。1個当てれる?マジで」
「1個当てれると思いますよ」
「ちょっと待って」
「当てれないから、当てれると思いますよ」
「当てれろ俺、当てれろ」

「トランザクションのときは、そのー、もうセレクトから全部ロックしたじゃないですか」
「えー」
「そこまでする必要がある?」
「アップデートだけロックするってことか」
「ほう」
「え、でも」
「いいですよ」
「アップデートだけロックしても、あー、そっか。だから別にアップ、え、待てよ、でもアップデートって冪等の処理だから、なんかデータモデルむずずいんじゃないか」

「ちょ、このへんでぼちぼちかい、答えに行くんですけど」
「はい」
「1つが2フェーズロックと呼ばれる」
「うん」
「えー、処理手法になりますね」
「ほう」
「で、ま、まずロックには2種類あって」
「うん」

「ロックって言ってるのは、その、セレクトしてるときにほかの人が読め、読ませなくするようなやつ」
「うんうんうん」
「2種類あって。えー、共有ロックと排他ロック」
「あー」
「という、えー、2つありますと」
「確かに。聞いたことある。うわ、説明できない」
「はい、ね。で、共有ロックっていうのは、共有ロックをかけたら」
「うん」

「共有ロックの処理はできるけど」
「うん」
「排他ロックのやつはやれない」
「あー、だから」
「排他ロック」
「リードオンリーだ」
「あ、そう」
「あれか」

「あ、うん?うん。リードオンリー?」
「編集中の、ほかの人が編集中なので閲覧のみできますみたいな、なんかロックするやつあるじゃないですか、ファイルとかで、共有ファイルみたいなやつ」
「はいはいはいはいはい」
「それ?」
「それですね、はい」
「あー」
「ですね」
「はいはいはいはい」

「で、まあ、これをやると、そのさっきのほんとに、はっ、えーっと、トランザクションって、まあ排他ロックだと思うんですけど」
「うん」
「その排他ロックの時間は縮められる」
「うんうんうんうん」
「ですね。はい。ただ」
「はい」
「あ、で、これの、はっ、えーっと、2フェーズロックはMySQLでシリアライザブルっていう」
「うん」

「ま、直列処理をするような設定をすると、この2フェーズロックになります」
「うーん」
「で、ただですね、これもつ、す、とんでもない弱点があって」
「はい」
「これあの、セレクトするときに共有ロックかけるんですけど」
「はい」
「僕がセレクトします、共有ロックしました」
「はい」

「のりさんがセレクトします、共有ロックしました」
「はい」
「で、僕とのりさんが2人とも共有ロックしてます」
「はい」
「で、僕が、じゃあ次にアップデートをかけるために排他ロックをしようと思うと」
「はい」
「すでに共有ロックがかかってるので排他ロックができなくて」
「はい」

「えー、共有ロックの解放待ちになって」
「えー」
「のりさんも同じようなことがなってデッドロックが起きるっていう」
「おいおいおいおい」
「はい」
「共有」
「ことになるので」
「共有ロックかかってるのに共有ロックかけれるんだ」

「あ、共有ロックはかけれます。共有ロックに対して共有ロックかけれる、かけれるんですけど」
「へー」
「ま、なのでそのロック時間自体はまあ短くはなるけどデッドロックのリスクがあるから」
「うん」
「ま、デッドロックというか、まあなんか時間で1回ロック解放して。で、ま、もう1回リトライさせるみたいな処理をちょっとアプリ側でやってあげる必要はあるんですけど」
「うん」
「はい。ま、MySQLのシリアライ、It'sapoolっていうのを使うと、まあこういう2フェーズロックという形で」
「うん」

「えー、直列処理をやろうとしてくるっていう」
「うん」
「のがまあ2、1つですね」
「えー、なんか聞いた感じさ、ちょ、2つ疑問があるんですけど」
「はい」
「まずなんか聞いた感じ、えー、どっちが良いのかあんまりピンとこないっていうのと」
「はい」
「えー、もう1個は、例えばさっきのなんか、えー、アップデートの処理とかだったら、えーっと、例えば在庫を10から2に更新するみたいな、あったじゃないですか」

「うん。はい」
「でもそれって、アップデート分ってなんか冪等処理だから元が10だろうがなんだろうが、アップデートで2にかけたら結局2になるから、なんかこう、なんて言うんだろう、排他ロックでもなんか違う問題起きそうだなっていう」
「あー、確かにアップデート分だとそうなるのかな。なんか」
「どっちかっていうとなんか」
「どういう書き方すんだろうな、はい」
「うん、インサートなのかな」
「アップデートの中でも、まあ書き方いろいろあると思うんですけど」
「うん」

「今の在庫数引く購入数を、なんか変数かなんかで入れるんですよね、きっとね」
「うんうんうんうん。あー、そっか。じゃあアプリケーション側で計算した値を次アップデートしようとすれば、まあ確かにあれマイナスになるじゃんつってなんか検知できるはできるか」
「うーん。か、もしくは冪等処理だとまずいこともあるんですよね。多分冪等に書くことはできると思うんですけど」
「うん」
「同時に書き込みをしたことによって、ほんとは在庫10個しかないのに16個出さなきゃいけなくなってることにもなりますよね、多分、冪等処理だと」
「うん」
「えー、なのでちょっとそのへんは、を、ま、直列とかにして回避、回避できるって話か」
「うーん」

「うん。で、この2フェーズロックも結構デッドロック発生するから良くなさそうじゃんっていうふうにはまああるんですけど」
「うん」
「ま、ほんとになんで、そのさっき言ったとおり、デフォルトだと2フェーズロックって実行しないようになってて」
「うん」
「なぜなら、やっぱしパフォーマンスに懸念があるから」
「あるんだ」
「うん」
「うん」

「やっぱ直列処理って重いんすよね」
「うんうんうんうん。わかったぞ、じゃあ。もう1個のやつ」
「お」
「行単位のロック」
「行単位のロックは、今までもずっとそう」
「今までもずっとそうなんだ」
「はい」
「じゃあわからんな」

「直列処理もそうですね、はい。えー、残りの1個はですね」
「うん」
「SSIと呼ばれる手法なんですけど」
「SSI?」
「はい」
「シングルなんとかインストラクション」
「直列化可能スナップショット分離なんで」
「じゃあスナップショットアイソレーションじゃん、最後のほうは」

「そうです、スナップショットアイソレーションなんですけど、多分。シリアライザブルなのか。まあ、SSIと呼ばれるやつなんですけど」
「うん」
「これあの、なんかスナップショット分離っていうものをベースにした考え方で」
「うん」
「えー、最初になんかセレクトしてから更新すると思うんですけど」
「うん」
「んで、最後のコミット時に、このコミットするタイミングって私が最初に見を読み取ったデータベースの状態に対してやるよねっていうのをちゃんと検証してからコミットするっていう設定になってます」
「ほう」

「なので、さっきののりさんと僕の例で言うと」
「あー」
「えーっと、僕がセレクトかけて、のりさんがセレクトかけて」
「うん」
「かいちが、えー、アップデートでの、乗り換え、塗り替えて、で、のりさんが最後にアップデートしてコミットするタイミングで」
「うんうん」
「あれ?なんか最初に見た状態と違うんですけどって言ってエラーを出してくれるっていうのがこのSSIっていう」
「なるほど」

「動作モードになってます。ま、なので、で、この、は違うぞってなったらどうなるかっていうと、えー、まあ基本的にリトライ処理をかけますね。またのりさんがセレクトからやり直して」
「うん」
「で、リトライをかけて、で、再実行するみたいな」
「うーん、なるほど。なんかこれまた早いかどうかピンとこないな、なんか」
「ほう」
「え、なんて言うんでしょう」
「時間もあるけど、はい」
「うーん、なんて言うんだろうな。例えば同時に実行、同時に実行することを考えすぎてるのかもしんないけど」

「うん」
「えー、例えばじゃあなんか同時に実行するじゃないですか」
「はい」
「で、えー、おや、最初と違うぞって言って書き換えるのと、最初から待って直列で動くのってなんかスピード的になんかそんなに変わらないなっていう感覚があるんですけど、そんなことないですか」
「うん。えーっと、多分合ってて、衝突率によってどの手法にするかみたいなとこが変わってくると思うんすよ」
「さよう。なるほど」
「うん。はい」
「あー、そっか。だから衝突率」

「そう、これらの」
「うん」
「そう。これらの、その、しゅ、3つの手法今紹介しましたけど」
「うんうん」
「書籍の中では、まあトレードオフですよと」
「うん」
「で、えーっと。例えば、その1回のトランザクションがすごく短時間で終わるすごいシンプルな処理だったら直列でもいいんじゃないかと」
「うん」

「言ってますし。え、一方で、まあ少し時間がかかったり」
「うんうん」
「する、かつ、まあそこまで、えー、なんて言うんでしょうね、デ、データベースの処理のキャパシティ、まあリトライ何回も叩かれてもまあ大丈夫だったらSSIでいいし」
「うんうんうん」
「いや、あんまり叩かれると困るんだったら2フェーズロック。みたいな記載だったと記憶してます」
「なるほど。ま、状況に応じて」
「はい」
「メリ、あのー、どれが1番最適化が結構変わってくるって感じなんすね」

「そうですね」
「うーん」
「ただ今言ったその衝突率がうんぬんみたいな話とかって、トランザクションが時間かかるかかんないみたいな話って」
「うん」
「僕はあまり今までの開発をしていて検証した記憶がなくてですね」
「うんうんうんうん」
「結構アーキテクチャーの、あ、違うわ。結構アーキテクトの嗅覚によって変わるんじゃないかなと。変わるというか変えなければいけない領域なのかなと」
「うん」

「思ったりしています」
「あとはまあ計測によってテストするとかね。同じ状況を。同じ状況を再現するのむず」
「ですね。で、この2フェーズロック、MySQLのシリアライザブルって言いましたけど、このSSI、最後のやつはPostgreのシリアライ、シリアライザブルです」
「うーん」
「なんでこれ変えようと思ったら多分データベースエンジン変える必要があります」
「あ、そのレベルで」
「はい」
「なるほど」

「なんで多分最初に決めなきゃいけないんでしょうね、きっとね」
「うーん」
「はい。まあみたいな感じで、えーとちょっとAssetの穴、まあ例えばCっていうのはアプリケーションレイヤーで保存、えーと保証しなければいけない一貫性もあるし。えー、Iについてもデフォルトだと最初の例みたいに分離性っていうのは保証できてないからうまく直列化可能な処理にしてあげる必要があるし。みたいなところをちょっとお話しさせていただきました」
「うんうんうん」
「で、またちょっと最初の問題にも立ち戻って、まあどういうことができるかっていうのを、まあ最後に答え合わせ的なところなんですけど」
「はい」
「えっとー、結局その直列化可能うんぬんみたいな話をしておきながら、多分実際にやるんだったら」
「うん」

「えー、SQLをAtomicな処理に変えます」
「SQLをAtomicな処理に変える」
「はい。セレクトして在庫の数数えて、こうアップデートかけるんじゃなくて」
「うん」
「最初からアップデート分で」
「うん」
「えー、UpdateProductsSet」
「うん」

「で、その次の値はなんかその在庫を購入数、在庫引く購入数にして」
「うん」
「で、IDが合ってるかと、あとはストックが購入数より多いかっていうそのWare条件を入れると」
「うん」
「Wareの中でその在庫より購入数が多いことが保証されるから」
「はい」
「まあ安全にアップデートかけれるよねっていうのがまあ多分最初のeCommerceの例だと正解」
「はい。引っ掛け問題じゃないですか」

「なんですか」
「引っ掛け問題じゃないですか」
「引っ掛け問題です」
「引っ掛け問題じゃないですか、これ」
「けど、正直あんまり僕はちょっと恥ずかしながら気にして書いたことがなかったんで、こういう」
「うんうんうんうん」
「ところですね。ちょ、気をつけようって震えながら読んでました」
「いやー、なるほどなー。やっぱデータベースって奥深いなー」

「深いっすね。で、あとなんかやっぱ、あの、今思うと」
「うん」
「なんかチケットの購入サイトとかってなんかやったことありますか、その発売日、発売日の発売時間瞬間になんか押してなんか買った経験ありますか、のりさんって。チケットにも限らず」
「なんかあるよ。あのー、あれでしょ。1月1日のさ、モンストのガチャみたいなことでしょ」
「えーっと」
「違うかな、あれは」
「あれは」
「あれはとんでもないキャパシティでどうにかなってるからなー」

「あー、まあそう、そうだな。ちょ、のりさん使うかわかんないんですけど」
「限られたリソースを奪い合う系のやつってことよね」
「そう」
「うーん、なんだろうな」
「モンストって最悪ね、あんなんね、ガブリエルがね、予定より出ちゃいましたでも別にね、最悪大丈夫っすから」
「まあ確かに。ガブリエル、懐かしいな」
「はい。僕が経験あるのはNintendoSwitchの予約販売なんですけど」
「うんうん」

「あれ、何時に発売しますって言って、ポチって、もうな、時間になった瞬間押すと」
「はい」
「なんか順番待ちですみたいな」
「うんうんうん」
「ページになんか飛ばされて。何人待ち、何人待ちみたいな人数がだんだん減ってって」
「うん」
「で、それで、えーと人、列が、自分の番になると購入ページに飛ばされて購入してみたいな流れになるんすけど」
「うん」

「あれも結局平行で、まあもちろんそのサイト自体の負荷を軽くするのももちろんあると思うんすけど」
「うんうん」
「あとはデータベースの処理的に平行に実行されてなんかどっかでバグるのを防ぐための、まあ1個のやり方なんだなっていうのを、なんか今思えば」
「うーん」
「このショーを見ながらなんか思ってたりしましたね」
「あー」
「まあもちろんサーバーリソースを制御するのはある、あると思うんですけど、もちろん」
「うーん。あ、ちなみにちょっと身近にあったあの、そういう系のやつだとは。あれはどうすかね」

「はい」
「あの、家の近くの小児科」
「小児科、はい」
「の外来、ネット予約ができるんですけど」
「はい」
「朝8時からしか予約できないみたいな制限かかってるんすよ」
「へー」
「で、えー、ちょっとでも遅れるとめっちゃ時間が後になるんですけど」

「いやー、激戦区なんすね」
「そういうことっすか」
「え、いえ、待たされてるわけではなく。あ、でも、えーと、遠からずで、その予約枠みたいなのもすごい大事なんすよね」
「うんうんうんうん」
「だって競合したら超大変なことになるんで」
「確かに。ダブルブッキングとかね、1番テンション下がるからね」
「そうです、そうです」
「うん」

「で、まあそのね、小児科の病院の予約ぐらいだったら1日に来るリクエスト数も多分高が知れてると思うんで」
「うんうんうん」
「その辺はね、多分直列でもそんなに問題ないでしょうね」
「うーん」
「日本全国、世界中の人が一気に来るとかだとね、多分問題あると思うんですけど」
「確かに」
「はい。まあなので本当に自分が開発するアプリケーションの性質によってちょっとこの辺考えていこうぜっていう7章でした」
「なるほどね」

「ぜひ今日も選んでみてください」
「いやー、データベースなー」
「ちょっと半分ぐらいしか話してないんすけど、その書籍の内容の。ちょっと深すぎて」
「深いね」
「深い。深いなー」
「過去1番深掘りしてるんじゃない、その本」
「あ、そうかもしんないっすね」
「ね」

「何回やってんだろう。まだあるし」
「まだ結構あるでしょう」
「半分ぐらいは行ったかな」
「うん」
「はい。まあまだあります。まだお楽しみに。ちょっとどんどん話がコアになりすぎてエピソードになりしづらいかもしんないですけど」
「うんうん」
「また共有させていただきます。ちょっとね」
「ありがとうございます。はい」

「アフタートークなんすけど」
「おお、出た。はい」
「はい。ちょっといよいよ来週から本気のワンオペが始まるんですけど、育児が」
「おおー」
「いまだにどうやったら回せるか分かってないんですよね」
「ワンオペね。え、仕事は」
「フル」
「フル?」

「フルタイムリモートワーク」
「仕事フルタイムリモートワークワンオペ?」
「はい」
「えぐいね」
「ほんとっすよね」
「えぐいね、それはだいぶ」
「で、なんか2人目の子どもが生まれるので、妻が里帰りで実家に帰って、僕と子どもの2人暮らしてワンオペ育児しなきゃいけないんですけど」
「うんうん」

「子どもが何かをさしたのか知らないんですけど」
「うん」
「最近すんごく甘えん坊で」
「うん」
「手離れが悪いんですよね」
「手離れが悪い。まあそういう年頃なんじゃないですか」
「はい。まあそういう年頃なのもあるかもしんない」
「うん」

「そう」
「うん」
「まあどうにかしなきゃいけないからどうにかしますけど」
「うん」
「どうにかなるかなーっていう不安の、不安を持ちつつ」
「うん」
「まあどうにかちょっとひまプロのほうも回していければなと思うので」
「なるほどね」

「はい。なんか個人的にね、ちょっとまだジャストアイディアなんですけど」
「はい」
「まあもちろん今読んでるこのデータベースアプリケーション、あ、違う、データ思考アプリケーションデザインのほうは読み進めていくんですが」
「うん」
「まあちょっとね、適宜ソフトスキルとかもちょっと挟みながら」
「うん」
「やっていけるといえるなと思っているところでございます。ここ1か月ぐらいかな」
「あー」

「いや、1か月半かな」
「ちょっと学習強度を下げて」
「そう」
「うんうんうん」
「あと順平頼んだ。あいつはまだなんか誰にも言ってないから僕らも言いませんけど、おもしろいことしてるんで」
「そうですね」
「本当に」
「いや、でもこの番組につながる経験をしてるかどうかはまだちょっと怪しいラインだけどな、あれ」

「いやー、乞うご期待ですよ、本当に。彼は非常におもしろくてすごい人間です」
「そうですね」
「はい」
「ワンオペかー。なんか夢中になるおもちゃとかないんすか。無限にこれで遊ぶみたいな」
「あー、えっと、親がいれば遊ぶんすけど、やっぱ親がいなくなるとね、だめなんすよね」
「うーん」
「その、はい。キッチンになんて言うんだろう、ベビ、なんて言ったら、その、子ども入れないゲートみたいなのがあるんすけど」
「はいはい」

「もう子ども入れないゲートがの向こうに行ったりとか、あとトイレ行ったりとかするともうブチギレですよね」
「そうなんだ」
「ブチギレ」
「そんな、同じゾーンで仕事は進められないんすか」
「あ、仕事は、あ、でも保育園には行ってる、行くんで」
「ああ、そういうことか」
「はい」
「ああ」

「日中は別にね、大丈夫なんすけど」
「はいはいはい」
「ちょっとね、仕事以外の時間でね、何もできないんすよね、多分」
「あ、そういうことか」
「そう」
「あ、はいはい」
「夜寝かしつけしたあとにいろいろ、なんだ、ご飯作ってとか」
「うん」

「家事を進めて」
「うん」
「あと、ちょっと別ですけど、この前あの子ども寝てて家にいたんですけど、隣で仕事することはできましたね」
「おおー」
「うん。なんかテレビ見さしたけは無限に、テレビ見さしたけは無限に大丈夫です」
「うーん」
「はい。けど、あの、ちょっとあんまりやりたくないっていうだけで」
「ああ。あの、それやると俺がテレビ見ちゃうからな」

「いやいやいや」
「うん」
「え、何おもしろいテレビ見せてるんですか」
「子ども用のやつは見ちゃうんだよな、なんか気づいたら」
「もっとよくわかんない。あのー、最近の子どものブームはですね」
「うん」
「えー、ミニカーが斜面をす、ひたすら滑り降りる。なんか様々なミニカーが斜面をすれ、滑り降りるだけの動画」
「うん。へー。ピタゴラスイッチみたいなこと」

「いやいやいや、もうそんな凝ってないです。そんな凝ってない」
「そんな凝ってない」
「はい。ダンボールの中にパンパンのいろんな種類の救急車のミニカーが入ってて」
「うん」
「そのいろんな種類の救急車のミニカーを1台ずつ、えー、1メーターぐらいのちょっとした斜面をシャーって降りてる様子を」
「へー」
「シャー、ガタンってなってる様子が10分ちょいぐらいの」
「うん」

「流れ続ける動画」
「うんうんうん」
「これはまってて。再生数8000万回とか言ってんすよ」
「8000万回。えー」
「発明すぎる」
「ブルーノ・マーズじゃん」
「ブルーノ・マーズってもうちょっと言ってないからな」
「奥行くか」

「あの」
「うん」
「でもそれで飯食ってる人がいるのもすごいなって思いますね。なんか天才というか」
「子ども用のやつってあれでも広告週に入んの?」
「あー、確かに。入んないとかあるのかもしんないっすね。どうなんでしょうね」
「なんか子どものやつあんまり広告入んないイメージだけど、どうなんだろうな」
「確かに。かつてはそうかも。まあかつてはっていうか今はそうかもしんないっすね」
「うーん」

「その動画8年前とかに上がってたやつで」
「うーん」
「本当に多分撮影コストもかかってないしおもちゃ代も多分1万円弱だし」
「うん」
「そんな言ってねえの多分。4000円とかかな。天才だと思いましたね、ほんとに」
「なんかあれだよね、多分見るのが子どもだからさ、なんか広告主が集まんなそうだよね」
「確かに。あー、どうなんでしょうね。でも、えー、どうなんでしょう。でもあれっすよ、のりさん」
「はい」

「スーパー戦隊のCMちゃんと流れてたじゃないですか、テレビは。おもちゃのCMは流れそうですよね」
「確かに。スーパー戦隊はさ、やっぱさ、あのイケメンの俳優が出てくるっていうところからお母さん層が見るからね」
「子どもがこれ買ってじゃなくて、やっぱお母さんがその場にいないといけないのか。YouTubeは確かにパーソナルだから」
「うん」
「広告効果弱いのか」
「あんまそこに、てかあれだよね、多分、うーんと、見てる層がより明確だからさ、なんかここに広告出したいっすってあんまなんないような気がするな」
「確かにね。あー、なるほど。それはありますね」
「うん」

「さすがになー、社会がどんだけ進んだとしても子ども自身がお金払えるような」
「うん」
「子どもっていうのも、幼児が子どもほどお金払えるような世界にはならないでしょうからね」
「うん。やっぱテレビってこうやっぱ、やっぱみんなで見るよねっていうのがあるよね」
「あー、確かに」
「うん」
「YouTubeそうじゃないっすからね」
「うん」

「なるほど。あ、いいですね。なんかちょっとあんまり思ったことないことを」
「はい」
「って世界がひらい、ちょっとだけ広がりました」
「ちょっと広がりましたか」
「広がったと思いました。広告ね、なるほど」
「はい」
「なんかそういう意味だと、なんかSNSとかだとやっぱ枠広いというかターゲティングしやすいからやっぱいいんだろうな」
「SNS?」

「広告、なんて言うんでしょう、その子ども向けというか、なんて、なんて言えばいいんだろうな」
「うん」
「えー、なんか街中の看板、だって渋谷のね、看板とかだともっと雑に広告できるというか」
「うん」
「雑なターゲティングでやれるかもしんないですけど」
「うん」
「やっぱSNSは全部やっぱフィットしたというか、なんかほんとに狙い撃ちなんすね」
「な気がするね」

「うん」
「まあ近くのスーパーのCMとか流れるときあるからな」
「テレビ?」
「うん」
「YouTube?」
「YouTube」
「えー、すご」
「ね」

「そうなんだ」
「大宮何々店みたいな。えーみたいな」
「あー、ローカルっすね」
「そんなピンポイントでやるのっていう」
「スーパーってそんなCM打つんだ」
「まあでかいとこよ」
「大体雑、雑棒とかだと思ってた」
「あの、八日堂とかそのレベルのやつ」

「あー、まあでもすごいわ」
「うん」
「へー。ぜひちょっとひまプロにもCMお待ちしてます」
「おお、あ、ぜひ。八日堂さんお願いします。はい」
「ぜひ。お願いします。では締めます」
「はい」
「ハッシュタグひまじんプログラマーでSNS、NEXTでフィードバック募集してますので、本日のエピソードの感想とか、えー、ありましたらぜひお気軽にお願いします」
「データベース、一緒に極めたいよっていう方もぜひお願いします」

「何卒。あとはエピソードの説明欄からGoogleフォームで番組の予防を感想、質問お待ちしてます。えー、そうですね。えー、順平、今何してるのっていうところ気になる方いたらぜひお便りお願いします」
「うん。まあなくてもきっといつか話します」
「そうっすね」
「うん」
「えー、あとはエピソードではなくチャンネル説明欄からSlackオンラインコミュニティ、ひまプロ談話室の参加申し込みフォームございますので、エンジニア友だち作りたい、ワイワイしたい、あとは、まあたまーに開催してるLT会出てみたいよという方いましたらお気軽にご参加お願いします」
「こちらお申し込みいただくとフォームに参加リンクが付いてます」
「ちょうど7月6日にやるって言ってましたね」
「です」

「ちょうど。うん。きっとこのエピソードのほうが早いはず」
「数日早いと思う」
「はい。え、最後に各種ポッドキャスト、プラットフォーム、フォロー、高評価もお願いします」
「励みになりますので、ぜひともご協力よろしくお願いします」
「お願いします。それではまた次回」
「バイバイ」
「さあ皆さん、次の商品は目玉商品です。こちら、めちゃくちゃでかいエンターキー」
「うわー、おっきい」

「これがあるとストレス発散、生産性アップ、快適な睡眠も」
「え、枕にしちゃうんですか」
「こちらの商品はお値段なんと1,024円」
「わーお、2の10乗」
「そして今、番組終了1時間以内にGoogleフォームよりお便りを送った方はちっちゃいスペースキーも付いてきまーす」
「ポケットに入れて持ち運べますね」
「番組の高評価、フォローもすると会員割引なんと90%オフ」
「え、ほぼタダー」

「今すぐご応募を」