ユユユユユ

webエンジニアです

activerecord で一括更新を行うときの選択肢をベンチマークで比較してみた

 Rails を使ってある程度の大きさのレコード群を一括更新する処理の実装方針を考えていた。愚直にイテレートして一件ずつ update していくのは論ずるまでもなくバッドプラクティスであるとして、その他の選択肢の優劣は検討してみないとよくわからないというのが正直なところであったため、ベンチマークをとって調査してみた。この記事はその記録である。

TL;DR

  • activerecord-import を選択する積極的な理由はなさそう
  • update_all で実装できるのであればそうするのが一番

方針

 ほぼ裸のテーブルを作成し、n件のレコードを一括更新する。nは任意の自然数でいいが、今回は10,000件と100,000件でそれぞれ調査してみた。

 比較対象は以下の5つ。ただし素の .update については最初から期待しておらず、ほとんど参考記録としての扱いとなる。

作ったもの

github.com

結果

https://github.com/sato11/benchmark-bulk-update-rb/blob/master/README.md

解釈と所感

 まず目に付くのは、 .import.upsert_all はレコード数におおむね比例して処理時間と消費メモリが増加しているが、 .upsert_all の方が20%ほどパフォーマンスに優れている点である。

 .upsert_allRails 6 で鳴り物入りで実装された新機能であるわけで、優れた結果を出すのは当然といえば当然といえる。いずれにせよ、これから実装を検討するうえでは、 activerecord-import を選択する積極的な理由は個人的には見出せない結果となった。

 他方、生の UPDATE 文を .execute に渡すコードと、 .update_all で同等のクエリを生成するコードは、パフォーマンスのうえで有意な差はほとんどなかった。メモリ消費量と実行速度において一長一短あるように見えつつも、レコードの数に関わらず一定のパフォーマンスが担保されていることもあり、これはほとんど無視できる程度の差異にすぎない。

 一行で書けるだけ .update_all に軍配が上がるだろう。.update_all ではカバーできないような複雑なクエリを扱うというのでなければ、 .update_all を使っておくのが安心そうである。

マルチプレクサとデマルチプレクサ

 The Elements of Computing Systems に沿って基本の論理ゲートを実装している。

jnsato.hateblo.jp

 NOT, AND, OR, XOR のような耳慣れた論理に加えて、 Multiplexor と Demultiplexor という耳慣れない回路が、基本の論理ゲートとして扱われていた。そもそも論理ゲートというものを、「2つの入力を1つの出力に合成するもの」のように捉えていた僕にとっては、複数の入出力を持ちうるこれらのゲートは異色の存在に思われた。ノートの書写しにはなるが、TILとして書いておきたい。

multiplexor

 マルチプレクサは、3つの1ビットの入力を受け取り、1つの1ビットの出力を与える。入力のうち1つはセレクタと呼ばれ、このセレクタがフラグとして立っているかどうかで、残りの2つの入力のうちどちらが出力されるかが決定される。

 真理表を書くと次のようになる。

input1 input2 selector output
0 0 0 0 (=input1)
0 1 0 0 (=input1)
1 0 0 1 (=input1)
1 1 0 1 (=input1)
0 0 1 0 (=input2)
0 1 1 1 (=input2)
1 0 1 0 (=input2)
1 1 1 1 (=input2)

 高級言語であれば、IFを使って条件分岐するような処理になる。

bool input1, input2, selector;

// 入力処理

if (selector)
    printf("%d", input2);
else
    printf("%d", input1);

 論理ゲートで実装する上では、こうなる。

f:id:jnsato:20200803222313p:plain

demultiplexor

 デマルチプレクサは、2つの1ビットの入力を受け取り、2ビットの出力を行う。今度も2つの入力のうち一方がセレクタであり、セレクタの値によって、出力ビットのどちらに入力ビットを出力するかが決定される。

 真理表は次の通り。

input selector output
0 0 00
0 1 00
1 0 10
1 1 01

 高級言語であれば、さながらこうなるだろう。

bool input, selector;

// 入力処理

if (selector)
    printf("0%d", input);
else
    printf("%d0", input);

 実装はこうなる。

f:id:jnsato:20200803223424p:plain

8月に取り組むテキストを紹介する

 月初めのモチベーターとして、準備したテキストを紹介していく。

f:id:jnsato:20200802152524j:plain

The Elements of Computing Systems

 Nand2tetris という愛称が与えられていて、知名度も高い教科書である。O’Reily から『コンピューターシステムの理論と実装』という邦題で出ている日本語訳も評価は高いようす。

 Nand2tetris という呼称が端的に表現しているように、 NAND という単一の論理ゲートを出発点に、CPU、メモリ、機械語アセンブリコンパイラ、OS までのコンピューターシステムを作り上げて、最後にはそのマシンの上でテトリスを実装するという方針の教科書である。

 骨太の一冊のように思われるが、実際には学部1年生でも取り組めるように、前提知識をほとんど要求しないように書かれている。学部レベルの計算機科学を学び直すという意味ではうってつけの教科書になる。ただし、「マシンを作り上げる」という目標のために、パイプライン処理やメモリ階層といった重要概念への言及が犠牲になっているとは指摘されている。

In seeking simplicity and cohesiveness, Nand2Tetris trades off depth. In particular, two very important concepts in modern computer architectures are pipelining and memory hierarchy, but both are mostly absent from the text. 1

 基本知識へのハンズオンとしてこれを読み終えて、アーキテクチャの全体像を手に入れた上で、より古典的な計算機科学のテキストに進むのがいいのだろう。とっかかりとしては申し分のないテキストであるようだから、時間をかけても完走したいところ。

『新装版 数学読本2』

新装版 数学読本2

新装版 数学読本2

 対数関数と三角関数について、ときおり参照する機会がありつつ、その度に検索エンジンに頼ってぼんやりと思い出すことを繰り返していた。受験勉強以来、数学の勉強から離れていたというブランクからくるコンプレックスを打破する上でもいい機会ではないかと、高校レベルの参考書を求めて、ここに行き着いた。

 著名なシリーズであるから、内容の品質には一分の心配もない。第一巻を飛ばしていきなり第二巻から着手するのはすこし腰が引けたが、遠慮していて勉強ができるかと開き直った。

 関数一般から取り組んでいて、二次関数の問題を解いたりしている。一日の終わりに、コンピュータを閉じて、裏紙に粛々と手計算をしていく時間には、日常から離れたリラクゼーションがあって、気持ちいい。

おわりに

 7月は C++ の参考書を中心に取り組んでいた。継続して C++ の勉強を膨らませていく、という方針もありえたが、結局のところ業務で使わないスキルであるから、モチベーションの維持に不安があった。

 計算機科学と数学については、そこに知識の欠落があるというコンプレックスは自覚してながら、「業務には必要ない」とか「いまの自分には必要ない」などと奇妙な正当化をして遠ざけてきた節がある。それでいて、「いつかは体系立てて学んでみたい」というようなことを飲み会の場で口走るようなこともあって、いくぶん迷走していた感じは否めない。

 短期的な投資対効果が見込める学習対象はほかにごまんとある。しかし今後長くコンピューターに携わっていく気持ちがすこしでもあるのであれば、できるだけ早くに計算機科学のイロハを学び直すのがいいだろう、とここのところ考えている。

 とはいえそれは、キャリアのための勉強とか、お金のための勉強とは思わず、好奇心を満たすための勉強と割り切って取り組むのが無難だろう。

 いま、計算機科学の観点からコンピューターアーキテクチャを作り上げるという課題を前にして、ここで学ぶひとつひとつの知識が、新たな視点をもたらしてくれるのだと胸をときめかせている。この感覚は、大学用の MacbookAir に初めて Ruby をインストールした日々の清らかな思い出に通じるものがある。

 モラトリアムの不安に押しつぶされていた時代に Ruby と出会い、のめり込むように学んできた結果としていまの自分があるけれど、その駆動力となったのは結局、好奇心であったはず。そして同じ好奇心を持って臨める対象であれば、なんでもある程度は習得できるはず。そう思って、一文無しの学生のように謙虚な気分で取り組んでいきたい。

NAND 演算があればあらゆる論理演算ができる

 NAND とは NOT AND のことで、真理値表は次のようになる。

x y x NAND y
0 0 1
0 1 1
1 0 1
1 1 0

 見ての通りの、 AND の否定形である。否定にすぎないから、論理学ではそう注目される演算でもないように思う。

 しかし電子回路の世界ではこの演算が中心の座を占めるといっても過言ではないらしい。というのも、 NAND 演算はそれ単独で、 AND, OR, NOT の論理を導出できるのである。AND, OR, NOT が使えればあらゆる論理が表現可能であるから、つまるところ NAND があればあらゆる論理が表現可能であるということにほかならない。

 例えば、 x NAND x を真理値表に表してみる。 x が同時に 0 と 1 であることはないから、二行で十分となる。するとこれが、 NOT x となっていることは一目瞭然だ。

x x NAND x
0 1
1 0

 これを利用して、 x NAND y を否定してあげると、 AND が導ける。

x y x NAND y (x NAND y) NAND (x NAND y)
0 0 1 0
0 1 1 0
1 0 1 0
1 1 0 1

 同じように、 OR はこう表せる。

x y x NAND x y NAND y (x NAND x) NAND (y NAND y)
0 0 1 1 0
0 1 1 0 1
1 0 0 1 1
1 1 0 0 1

背伸びして『Effective C++ 第3版』を読んだ

 ある Googler の投稿を読んでいて、見かけた本である。題字のフォント、表紙のデザインなど、飾り気はないのに力強いオーラを持つ装丁がただちに印象に残った。名著という評判も高いおかげで安心して読むことができたし、翻訳も丁寧な印象で、自然に読める心地よさはありがたかった。

Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI)

Effective C++ 第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTI)

 どのページでも実践的な開発の勘所を完結に提示してくれて、知識として興味深買った。例えば「メンバ関数カプセル化を弱める」という観点。メンバ関数は private なデータにアクセス可能であるから、カプセル化の観点からは非メンバ関数の方が安定するのだという。自分ではたいしてこだわりも持っていなかったが、言われてみれば理にかなっていて、「明日から使える知識」として印象に残った。

 ただ全体としてはあくまで、C++という言語を主題としているわけだから、そもそも入門したての僕にとってはいくぶん背伸びした内容だったことは否めない。仕事としてC++のプロジェクトに携わっているわけではないから、読んで得た知識を実践にフィードバックする機会もそう多くない。つまり知識の定着という意味でも、短期的に成果を得るということはあまり期待できないということで、いくらか残念に思う。

 現状の僕にとってのC++の用途は、多くとも数百行程度のコードで計算をさせるくらいの使い方にとどまっている。使い捨てのクラスは書いても、長く使われるクラスを設計したことはない。そういった経験不足のせいで、この本を十分に味わいつくすことはまだできないようだ。

 一方で、これからより多くを学んでいくにつれて、わかることがどんどん増えるのだろうなとは期待してしまう。そのためにはますます意識的にテクニックを身につけていけないけれど、そのさきでこそ再読すべき本がこれなのだと思う。そう思って、その機会がやってくるまでひとまずこの本はしまっておく。

『江添亮のC++入門』でC++の基本を学び直す

 競技プログラミングに触れるようになって、自己流ながら少しずつC++が使えるようになってきた。しかしきちんとした参考書を読んだことがなく、体系立てた学習もしたことがないのが気にかかっていた。学習といえば、AOJの教育コンテンツを少しやったばかりで、そのあとは実践問題を解きながら必要に応じて学んできた程度にすぎなく、それでは物足りないと思い始めて、入門の参考書をやってみることにした。

江添亮のC++入門

江添亮のC++入門

  • 作者:江添 亮
  • 発売日: 2019/09/20
  • メディア: 単行本

 数ある参考書のなかでこれを選んだ経緯について、初めて書影を目にしたときは、いくぶんギョッとさせられた。よくも悪くも潔い印象はある。正直にいって、はじめ手にとったときはこの装丁に圧倒されて、すぐに書棚に戻してしまった。しかし多くの入門書があるなかで、どれを選ぶかと判断しなければならないときに、実名と肖像を大きくフィーチャーしているこの本は、著者としての自信と覚悟がもっともあらわれているという点で強いフックになった。

 文章について、教科書や参考書というよりはエッセイに近い文体で書かれている。手取り足取りというような親切さはないが、付かず離れずの距離感で読者を先導してくれる印象はあった。リズムに慣れる必要はあるものの、慣れさえすればそう気にはならない。

 内容の方に目を向けると、C++についての記述に先立って、 GCCMakefile の説明を一通りカバーしてくれているのは親切に感じた。C++について自己流で学んできたのと同じように、ビルドについても見よう見まねで覚えてきたため、これらのトピックを付録ではなく冒頭で解説してくれるのは、僕にとってピッタリの進行であった。欲をかいていうと、 cmake がなんであって、どう使うのか、なんかもついでに教わりたい気持ちはあった。とはいえひとまずは make を覚えて手に馴染ませなさい、ということなのだろう。

 中盤の「アルゴリズム」の章で、それまで学んだ知識を動員して、標準ライブラリに含まれるような典型アルゴリズムを実装するのもいい教材だった。先行する章で学んだばかりのイテレータの知識を利用して、 for_each, find, count といったアルゴリズムが実装可能であると、手を動かしながら知ることができる。その過程では、これら標準ライブラリに含まれた関数が決してブラックボックスではなく、基本の知識だけでも十分実装可能なものである、という大事な認識も与えられた。「繰り返し処理には for_each を使いましょう」というような、すでに御膳立てされた道具の使い方を教える方式ではなく、その実装まで付き添って教えてくれるのは、非常に善意のある教え方だと印象に残った。

 ポインタの解説についても、「意味としてのポインタ」と「文法としてのポインタ」をよく区別しないまま捉えてしまうことが学習者の混乱の原因であると看破して、よく整理して解説してくれている。先に学んだリファレンスとの比較において、ポインタは機能としては大きくかけ離れたものではないとした上で、複雑に見えるのは文法が難しいに他ならない、としてくれるのは、安心感も納得感もある。要するに、ポインタがわからないと嘆くのは、ポインタの概念がわからないのではなく、文法を覚え切れていないということに他ならないのだろう。自戒も込めつつ、これには実感がある。

 と、ここまでは実践も含めてたいへん満足いくものであった。他方で、その先のトピックではちょっと置いてきぼりにされてしまったきらいがある。例えば、それまで C++17 を前提に進めてきた演習に、突然 C++20 の機能を使う、と宣言される場面があった。このため手元のコンパイラapple clang 11.0.3)でコンパイルできなくなってしまった。コンパイル手段を検討したり、C++17 で実装し直すのは、つまらない作業ではなかったが、学習スピードとしては著しく低下してしまった。

 ほかにもコンパイラの相性のせいなのか、サンプルコードをうまく動かせない場面はちらほらあった。ごまかしながら進めていたが、なんとなく動かして満足するのでは学習として意味がないなと思って、手を動かしながらじっくり読むのはやめにした。逐一検証していくことはせず、気になる部分だけを書き写して実行してみるほかは、ザッと読んで参考にするだけに留めておいた。

 というわけで、教材としてはおおむね満足しているが、後半、解説が駆け足になるにつれて、置き去りにされてしまった気分は否めない。入門というには高度に思われる話題も少なくない気がしたが、それ自体はそう悪いことではないと思う。それは言うなれば、大学の講義なんかで教授の話を一生懸命聞いているものの、だんだんと内容が発展していき、気づくとついていけなくなってしまっている、というようなものだと思う。そして経験上、こういったケースではあとになって教授の含意に気づく瞬間がふと訪れるものだから、その時までじっくり待てばいい。

 要するに、わからなかった箇所もちらほらあるが、わかる部分が皆無だったわけでは決してない。そして事実、新しく学べたことはたくさんあるのだから、まずはその新しい知識を応用できるようになることを目指すのが筋と思う。そのうち、わからなかったこともだんだんわかるようになってくるはずだし、そのようなときに、ここになにが書かれていたかを思い出して、適当に読み返せられればそれでいいだろう。

『キタミ式イラストIT塾 基本情報技術者』を読んだ

 大学生であったおり、就職活動に合わせてこの参考書を手に取ったことがある。そしてほとんど2割も読まずに匙を投げた。資格の存在を知るより先にプログラミングのアルバイトを始めていたから、資格試験の勉強では死んだ知識しか身に付けられない、と粋ぶっていたのだと思う。

 インターン先としてもぐり込んだある企業では、2つ年下のインターン生が応用情報技術者を持っているということがあった。すごいな、とは思ったけれど、そんな彼と同じ待遇で実務をさせてもらえるに足るだけのアピールを自分は持てているのだという自尊心を育てるだけで、相変わらず資格勉強は低くみていた。

 まあ、そのときにはそのときの視野の狭さがあったということで、それについてくどくどと書いても仕方がない。それよりも、かつてはひどく退屈に思われたのと同じテキストが、いかに体系づけられ、よく整理され、網羅的な参考書であったかということに新鮮な思いで気づけたということ、そのことを喜びたい。

 実に、計算機の基本をいかに知らずにいたかを繰り返し教えられた。半加算器と全加算器は言葉すら知らなかったし、補数を利用して減算を実現するというアイデアは、自分でそれを発想することはまず不可能だが、言われてみれば単純明快でたいへん気持ちがいい。クイックソートヒープソートまでカバーされていることには驚いたが、世間的にはこれらさえ基本の範疇なのだろうと襟を正す気分にもさせられる。

 要するに、情報技術者としての僕はまだまだ基本未満なのである。そしてそれを知って、かえって晴れやかな気分になれているところに僕の成長がある。

 最初の仕事に就くまでは、「実務経験」のような言葉を振り回して自分を大きく見せるのはひとつの戦略であった。資格試験を軽んじていたことは否めないが、それは自信のなさを隠す手段としての行為であったような気がしている。基数変換になんの意味があろうか? と息巻く様子は、数学嫌いの中学生のような態度だったろうと思う。しかしまさにイニシエーション的という意味合いで、それは僕が学生から社会人に足を踏み入れるための儀式として必要だったのではないかなともいまでは思っている。

 いま、「応用から基礎へ」と自分のテーマを定めてようやく、この資格のありがたみを知った。情報科での教育のない僕のような者にとって、これだけ網羅的に「基本」を学べるチャンスが、これだけアクセスしやすく提供されていることは幸せなことである。ネットをみわたすと python だとか aws の講義が無料で受講できたりして、それはそれで豊かな学びにはなるだろうが、電気信号レベルでの話から丁寧に、かつ体系的に学ぶ機会というものはなかなかない。それはキャッチーでなかったり、フックがないから、ということにはなるが、そうした技術をこそ「枯れた」と形容すべきなのだろう。はっきりいって、基本情報のテキストは「枯れた知識」のオンパレードである。墓場とみなすか甘味箱とみなすかは受け手次第である。

 この一冊をザッと眺めただけで学んだとするのも傲慢であるし、そんなことをいう気はない。しかしコンピューターを語るための基礎のボキャブラリーをひととおりインプットして、これでようやくスタートラインに立てた、というような実感はおおいにある。たとえば少し前まではちっとも使おうとすら思わなかったビット演算を、いまや当たり前のように使いこなせるようになっているところに、ほかならない自分の変化を見出すなどしている。

 仕事としてプログラムを書くうえで、それがどう便利にはたらくかはわからない。実際、低レベルの知識が要求される仕事をしているわけではないし、ここで得た基礎知識が仕事に直結するとは言わない。しかしそれでいいとも思っている。かつて退屈していた知識にあらためて向き直して、そのおもしろさに気づくことができたこと、そのことがなによりも自分の成長を感じさせてくれるし、この「おもしろい」をさらに掘り下げていくと、いったいそこにはどんな世界があるのだろうとわくわくさせられる。

 ひとまず出題範囲をひと巡りすることができたことになる。すでに持ち合わせている知識も多いから、わざわざ受験するまでのことはないようにも思うが、それでも僕は秋の試験を受けようと考えている。基本情報なんていまさらとっても履歴書に書いてどうなるわけでもないし、投資対効果という意味ではたいしたものにはなるまい。はっきりいって、そういった世俗の利益計算とは関係なく、試験そのものを目的として勉強したいという気になっている。誰に命じられるでもなく、またなんの利益があるわけでもなく、ただそれ自体を目的として学ぶ。ストイックなようでもいて、富豪的なようでもあるが、いずれにしても、そのプロセスを通り抜けた先に、また新しい自分を発見できるような予感がある。予感があるから、それに従おうという、それまでの話となる。