角待ちは対空

おもむろガウェイン

2021年

一瞬ブログ書くかぁと思ってもまぁ書かないでいいかなを繰り返した2021年でした。 自分の中でブログでなにか書くことは、それが是な組織にいたところが大きいなぁと実感した。まぁ2021年以前も大して書いてないけど。

生活

仕事も変えて住む場所も変えた。

誰が言ったかは知らないし間違って覚えてるかも知れないけど、人間が変わる方法の3つのうち2つ変えてもなお、自分が変わった気はしない。30年積み重なった習慣の力はどうしようもないのか。 どちらかといえば「君は他の会社では生きていけない」といわれてきたタイプなので、仕事を変えてもまぁ生きていけることは確認できたのはよかったけど、根本的な部分は変えられないのかと思うと陰鬱な気分になる。

まぁ自分の変化って言うのは現在進行形では認識できないものなのかもしれない。

読んだ本

科学哲学とフェミニズムの勉強をずっとしてた。ほんとうにずっとか?とおもってちゃんと調べたらここ半年だったけど、まぁ半年続けばもうそれは1年の1/2なわけだから今年のトレンドとしてしまって良いでしょう。

モチベーションの説明が難しいんだけど、(正であれ負であれ)心のザワつきを知識によって克服し興味を失いたいというのがある。小学生の頃2chのUnix板や物理板、数学板に憧れみたいな感情を持って接してたけど、大学生くらいに成長して知識をつけてから改めてみると拾う価値のあるものを見つける方が難しいと気づいて興味を失う、みたいな体験を無限に繰り返したいというのがある。

基本的には静かに暮らしたいんだとおもうけど、自分より知識のない人間を見下してないか?とかわかった風を装って引きこもってるだけではないか?という気持ちもあるので、まぁそこら辺のメタなザワつきもいずれ克服していきたいですね。

ところで科学哲学とフェミニズムの勉強の中で一番面白かったのは分析哲学の勉強でした。自分の職業的な背景含めて分析哲学の周辺にあったり背景になってる議論が身近に感じられいろんな興味の結節点になってた。

www.amazon.co.jp

見た映画

f:id:t_kyt:20211230105507p:plain

大体1~2週に1回のペースで見てた。冷静に考えるとコロナまっただ中にどうかと思うが映画館はセーフだと思ってたし、もっというならコロナだからまずいみたいな意識あんまりなかった。

「劇場版 少女☆歌劇 レヴュースタァライト」が圧倒的に良かった。やっぱり映画はまず映像だなと思っていてそこに関して満点だった、ガイナックス的な気持ちよさだとモチーフの視覚的な気持ちよさにパワーがあり見ていて引き込まれた。アニメであるが故の強さがあった。その上で解釈への欲望を点火するような作りになっていて見事にはまった。ちなみにTV版は未視聴だったけど帰ってすぐみたし映画も何回か見た。

自分はウテナが好きで今も定期的に見直すのだけれど、「ウテナ的なもの」としての好意的に受け取れた。過去何度か「ウテナ的なもの」はあったけどあまり受け入れられる物はなかった歴史のです。

来年

京都観光をしようと思う。

プライマリーキー(primary key)はシーケンシャルな値で良いと思うよ

zenn.dev

を読んでの感想です。「シーケンスナンバーをPKにする」以外の項目については言及しませんが、言及しないことは正当性や妥当性を保証していることにはならないです。

InnoDB(MySQL)を想定してます。が、原理は割と一般的なので他のDBでも適用できることが多いと思います。

追記:一般的とは分散でないような"普通の"RDBMSを想定してましたが、分散システム(distributed systemないしreplicated system)のような場合では話が違います。

なぜシーケンシャルな値がよいか

端的にいうと書き込み操作時にバッファープール(baffuer pool)に読み混む必要のあるページが少なくて済むからです。その結果書き込み操作時にバッファープールにページが存在する可能性が高くレイテンシー的に有利になる可能性が高いです。

バッファープール、ページ、btreeなど具体的にイメージできない人にとっては難しいとは思いますが、軽く説明しておきます。多くのRDBMSはディスクIOの遅さをカバーするため直接ファイルを読み書きするわけではなく、必ずバッファープールに読み出してから操作を行います。これはwrite時もread時も同じです。ページというのはざっくり言ってバッファープールに読み混む単位であり、btreeのノードもページ上で表現されています。だからバッファープール上にページが存在しない場合、一旦ディスクから読み混まなくてはならないため操作に時間がかかるようになります*1

InnoDBではレコードはプライマリーキーをキーとしてbtreeを構築してますので、ざっくり言ってinsert=btree上のノードを辿って適切なページにデータをおくということです。

バッファープールはメモリ上に構築されています。メモリはディスクに比べたら容量は少ないので、すべてのページをバッファープールに載せることはいずれ難しくなります。こうなるとバッファープール上に読み混まれたページは何かしらのポリシーによって入れ換えが行われ、不要なページはバッファープール上から追い出され必要なページが読み込まれます。InnoDBの場合はそのポリシーはLRU(の亜種)です。重要なことはbtree全部をバッファープールに乗せられない場合使用頻度の高いページはバッファープールに載っている可能性が高く、使用頻度が低いページは追い出されている可能性が高いということです。時間的局所性(temporal locality)といわれる性質です。

以上を踏まえてシーケンシャルな値かランダムな値どちらが良いかを考えると、ランダムな値の場合ランダムですので原理的にすべてのノードがバッファープール上に必要になります。すべてのページの使用頻度が同じくらいなので局所性がない状態です。どのページも同じ確率でバッファープールから追い出されていきます。すると書き込みの際、必要なページの内のどれかはバッファープールにない状態が普通になりますから、ディスクとのIOが必要になる可能性が高いのでレイテンシ的に不利になります。

シーケンシャルな値の場合は書き込みに必要なノードは1経路のみですから全体をバッファプール上に保持しておく必要はなく、ページがバッファープール上に存在することが大いに期待できます。書き込みと同時にページ全体(に近い範囲)を読み混むようなselect文が走っている環境であっても置き換えポリシーはLRUですので定期的な書き込みがあればバッファープールにのっていることが期待できます。

ページのラッチ(latch)

ページへの操作は競合状態を避けるためラッチ処理が行われます。同時実行制御です。InnoDBの場合MTR(mini transaction)という名前になっています*2。ですから1ページに複数の書き込み操作を同時に行う場合は実質的に1つずつしか実行されないので、異なる複数のページに書き込みを行い同時に実行できる場合と比べて確かに遅くなります。

--

話はそれますが結構一般的な問題ではあることから各RDBMS最適化の実装が入っています。

--

つまり局所的には件の記事に書かれている説明は正しいですが、実際的にはバッファープールが載っているかどうかの方が支配的であるため一見正しそうに見えて多くの場合ではバッファープールの事情を優先した方がパフォーマンス的には有利になるでしょう。

場合による

(自分の経験した)典型的なユースケースの場合、シーケンシャルな値の方が良いと思ってますが、すべては場合によります。「ページのラッチの差が重要である」かつ「データ量は多くないのでバッファープールにページがのりきる」という場面もありえないわけでもないです。そういうユースケースやテーブル設計は想像できますし想像できると言うことはありうるということでしょう*3。またアプリケーションの事情は常に正*4だと思っているので、アプリケーションの事情でプライマリーキーを選択しなければならない場合もあるかと思います。特に歴史的経緯があるならばなおさらです。遅いことがプロダクトの価値を毀損していないのであれば、DB的には正しくなくても周りとの一貫性を優先した方がプロダクト全体に良い影響があることはざらにあります。

べき集べからず集というのは「もっとも効果的にテクノロジーを使うために知らなければならない全体の20%」*5だと思っているので、べき集べからず集に対してアーキテクチャを説明して「議論は単純化はできない、場合による」と言ったところで求められているものとは違うわけで、あんまり効果的ではないと思っています。なので本心では「場合による」が正しいと思ってますが、あえて言い切るのであれば、「プライマリーキーはシーケンシャルな値を使え」です。

この議論はもう何回もされている

www.percona.com

これは2007年です。その後も定期的に話題にでる話なので探せばいくらでも出てきます*6。ちなみに議論の軸としてはシーケンシャルな値がいいのかと同時にサイズについての議論も盛んです。ただもうほとんど決着はついていてその結果がMySQLの(第2引数含めた)UUID_TO_BIN()対応だと思います。

*1:バッファープールに存在する=キャッシュが効いていて速くなっていると捉えることもできますが。自分はどちらかと言えばバッファープールに存在する状態がノーマルな状態だと思ってます。表現の問題なのでどちらでも良いですが

*2:PostgreSQLはLightweight Lock

*3:仮にあったとして自分だったらプライマリーキーにプレフィックスつけて擬似的にシャーディングすると思いますが、ふわふわした架空の要件に対して解決法提示してもしょうがないなという気持ちです

*4:というか人間含めたプロダクト全体のより上位の事情

*5:CAREER SKILLSの言葉

*6:「percona uuid」で検索しただけで4つくらいある

dotfile棚卸し2021

  • 自分はdotfileのリポジトリをpublicにできない側の人間だと受け入れる
  • alias g=git みたいなありがちだけど使ったことのないエイリアス消す
  • 逆に alias c='code' とかは使うし c. の打ち間違いがめちゃくちゃ多いから alias c.='code .' 設定する
  • gitのエイリアスも大体使ってないので消す。 open = !gh repo view -w -b $(git symbolic-ref --short HEAD) 入れる
  • シンボリックリンク貼るスクリプトは自作を止めてthoughtbot/rcmに乗り換える。rcmでできないことはやらない
  • Windows用のファイルは一旦諦める。なくなったら辛いものだけ手動でバックアップ作っておく
  • promptのカスタマイズはStarshipにする。できないことはやらない
  • Karabiner-Elements、iTerm2、Alfredの設定もgitで管理する
  • tmuxのステータスの右側一切見てないので set-option -g status-right "[#h][%m/%d %H:%M:%S#[default]]" くらいにする。多分次回は消してる
  • fzfとpecoを併用してたけどfzfに一本化する
  • tmux popupかっこいいのでfzfの選択画面に設定する
  • ghq.root をデフォルトの ~/ghq にする
  • zsh completionの管理がだるいので見なかったことにする。brewが良い感じにしてくれたり自前でどうにかしないといけなかったりしてめんどくさい
  • zsh_historyのバックアップをLaunchAgentsで設定する。ヒストリーないと生産性5割くらい下がるような生き方してる
  • brewでzsh入れるの止めてシステムデフォルトのやつ入れる

ターミナル環境にそこまでこだわりないのでなるべくデフォルトで過ごしたいけど無理にデフォルトに寄せるほどこだわりもない。VS Codeのターミナルで生活したいと思う一方、一本化もできないのでiTerm2使ってる。定期的にBash移行したいと思ってたけどMacOSのデフォルトがzshになってしまったのでモチベーションなくなった。

それはそうとなんか昔ほどこだわりdotfileをご紹介みたいなエントリが流れてこない。