東京Ruby会議に参加して、ネットが繋がらない!と嘆いている人を大勢見ました。
Ruby会議に限らず、最近の勉強会やイベントは公式のハッシュタグがあり、Twitterで感想や突っ込みを入れるのがお約束になっていますが、参加者の多いイベントではネットが繋がりにくくなることが増えています。
なぜ繋がりにくくなるのか、繋がるようにするにはどうすればいいのか、自分の経験を交えて少し考察してみます。
なお、無線通信の専門家ではないので、間違っていることを書いていたら指摘していただけると幸いです。

More »

ここのところqiitaの方ばっかり書いていて放置していたけど、たまにはこちらへ。

.tmux.confにnew-window -n pry pryと書いて自動的にpryのウィンドウを開いてたが、brew upgradeとかやってるうちに正常に起動しなくなった。
エラーメッセージが一瞬で消えてしまうので分かりにくいが、tmux new-window “pry;read v”とやればじっくり見ることができる。
それによるとどうやらrvmで入れたpryがインタプリタとして/usr/bin/rubyを起動しようとしてSEGVしているらしい。
Twitterで呟いて悩んでいたらサジェストを貰った。

おお?PATHの先頭に/usr/binが入っているので、rvmのrubyではなくシステムのrubyが呼び出されているようだ。

tmux内のプロンプトでecho $PATHすると正常なんだけど、これは

ということらしい。なるほど!
pryが起動していたのは[[ -s “$HOME/.rvm/scripts/rvm” ]] && source “$HOME/.rvm/scripts/rvm”が.zloginに入っていたため・・・なのかな?
とりあえず.zshenvに

を書き、.zshrcや.zloginからrvmの設定を削除したところ、正常に起動するようになった。

また、これらのファイルのどれが読み込まれるか、またその順番についてはこちらの記事が参考になった。

MySQLのJOINが遅いというのはよく言われるが、複数回SQLを発行するのとJOINするのがどちらがましなのか疑問だったので、実際どのくらい遅いのか試してみた。

Rails3.2のプロジェクトを作成し、適当なモデルを作ってconsoleでSQLの実行時間を見る。
サンプルコードはgithubに置いた
モデルはUser -< Item -< Extraで、Userは100、Itemは10ずつで1000、Extraは10ずつで合計10000のレコードを作成することにする。
seed_fuのフィクスチャを使い、rake db:seed_fuで一気にレコードが作成されるようにした。

この状態(commit:830f6dae26189d4ea83b8753471a166712d50568)で全てのエントリを取得させてみた。

User全件(100件)

> User.all.count
# SELECT `users`.* FROM `users`
=> 1.0ms

Item全件(100*10件)
1.JOINした場合

> User.joins(:items).all.count
# SELECT `users`.* FROM `users` INNER JOIN `items` ON `items`.`user_id` = `users`.`id`
=> 3.2ms

2.JOINせず複数回SQLした場合

> Item.where(:user_id => User.where(:id => {:not => nil}).pluck(:id)).all.count
# SELECT id FROM `users` WHERE (`users`.`id` IS NOT NULL)
# SELECT `items`.* FROM `items` WHERE `items`.`user_id` IN (1..100)
=> 0.6ms + 4.5ms = 5.1ms

Extra全件(100*10*10件)
1.JOINした場合

> User.joins(:items => :extras).all.count
# SELECT `users`.* FROM `users` INNER JOIN `items` ON `items`.`user_id` = `users`.`id` INNER JOIN `extras` ON `extras`.`item_id` = `items`.`id`
=> 35.4ms

2.JOINせず複数回SQLした場合

> Extra.where(:item_id => (Item.where(:user_id => User.where(:id => {:not => nil}).pluck(:id)).pluck(:id))).all.count
# SELECT id FROM `users` WHERE (`users`.`id` IS NOT NULL)
# SELECT id FROM `items` WHERE `items`.`user_id` IN (1..100)
# SELECT `extras`.* FROM `extras` WHERE `extras`.`item_id` IN (1..1000)
=> 0.6ms + 1.8ms + 30.9ms = 33.3ms

このケースだとあまり差が出ないので、Extraの件数を10倍にしてみた。(commit:96ee43e9319a363666033ac725950283bb80fab8

Extra全件(100*10*100件)
1.JOINした場合

> User.joins(:items => :extras).all.count
# SELECT `users`.* FROM `users` INNER JOIN `items` ON `items`.`user_id` = `users`.`id` INNER JOIN `extras` ON `extras`.`item_id` = `items`.`id`
=> 358.9ms

2.JOINせず複数回SQLした場合

> Extra.where(:item_id => (Item.where(:user_id => User.where(:id => {:not => nil}).pluck(:id)).pluck(:id))).all.count
# SELECT id FROM `users` WHERE (`users`.`id` IS NOT NULL)
# SELECT id FROM `items` WHERE `items`.`user_id` IN (1..100)
# SELECT `extras`.* FROM `extras` WHERE `extras`.`item_id` IN (1..1000)
=> 0.7ms + 1.9ms + 303.0ms = 305.6ms

件数が増えるほど差が広がっている。件数が多い時はJOINしない方が良さそうではある。
まぁ、300msもかかるようだと他の高速化手段を取るべきだろうけど。

ついでにindexを追加してみた。(commit:bac53fb2569b5a681a6bacad3e8c13535e4aa141

Item全件(100*10件)
1.JOINした場合

> User.joins(:items).all.count
# SELECT `users`.* FROM `users` INNER JOIN `items` ON `items`.`user_id` = `users`.`id`
=> 4.0ms

2.JOINせず複数回SQLした場合

> Item.where(:user_id => User.where(:id => {:not => nil}).pluck(:id)).all.count
# SELECT id FROM `users` WHERE (`users`.`id` IS NOT NULL)
# SELECT `items`.* FROM `items` WHERE `items`.`user_id` IN (1..100)
=> 0.7ms + 4.7ms = 5.4ms

Extra全件(100*10*100件)
1.JOINした場合

> User.joins(:items => :extras).all.count
# SELECT `users`.* FROM `users` INNER JOIN `items` ON `items`.`user_id` = `users`.`id` INNER JOIN `extras` ON `extras`.`item_id` = `items`.`id`
=> 212.1ms

2.JOINせず複数回SQLした場合

> Extra.where(:item_id => (Item.where(:user_id => User.where(:id => {:not => nil}).pluck(:id)).pluck(:id))).all.count
# SELECT id FROM `users` WHERE (`users`.`id` IS NOT NULL)
# SELECT id FROM `items` WHERE `items`.`user_id` IN (1..100)
# SELECT `extras`.* FROM `extras` WHERE `extras`.`item_id` IN (1..1000)
=> 0.6ms + 3.3ms + 556.9ms = 560.8ms

む、逆転した。

以上はローカル環境で適当にやっただけなので、そのうちAWSのインスタンスでも立ててちゃんと調べよう。

追記:分かりやすいようにSQL入れました。

久々にEmacsをビルドした。もちろんCocoa Emacs。
手順はほぼこの通りでOK。

久しぶりにinline patchを当ててみたが、やはりauto-saveとぶつかった時に落ちる。
(auto-save-buffersは使っていないんだけど)
これを回避するパッチがmacemacs-jpで流れていたので当てる。

一応、patch -p0で当てられるパッチを作ったので置いておく。

一通りパッチを揃えたら以下の手順でビルド。


patch -p1 < ../emacs-23-lion-fullscreen-test.patch patch -p0 < ../inline_patch-svn/emacs-inline.patch patch -p1 < ../fix-shiftmodifier-patch-for-emacs-inline-patch.diff patch -p0 < ../fix-auto-save-crash.patch ./configure –with-ns –without-x make bootstrap make install [/bash] Mac Mini(Core2Duo 2.4GHz/8G/SSD)でビルド所要時間13分くらい。 思ったよりも速くなってないけど、まぁCore2Duoだしこんなもんか。i7のMiniかiMac出たら欲しいな。

varnishとnginxを使っているサーバをマイグレーションすることになり、今まで外部のLBを通していたのを直接処理することになった。
そこで問題になるのはSSLの扱い。varnishはSSLを扱えないため(作者はopensslのコードはクソだ、と一刀両断している)、httpsのフロントエンドとしては使えない。
そこで順序を入れ替え、nginxをフロントエンドに、varnishを挟んでunicornに投げるようにした。

More »

真空断熱マグがへこんだので買い換えた。
何となく毎回別々のメーカーのを買っているので、ここらでちょっとレビューしてみる。
保温性能とか重量とかはだいたい一緒なので、その他を中心に。

サーモス「ケータイマグ」

少し太めで持ちにくいが、その分高さは低い。
塗装がはげやすく、すぐボロボロになる。リペイントとか楽しめる人にはいいかも。
蓋のロックはあけやすく、ゆっくり開くのも良い。
飲み口のパーツが掃除しにくく汚れる。

TIGER「サハラマグ」

蓋のロックが固くて開けにくい。勢いよく開く上に、角度が足りず鼻にぶつかる。(サイズや人によるかもしれない)
飲み口は一体化されていて掃除しやすい。
ボディがコーティングされているので塗装がはげない。

象印「ステンレスマグ」

容量が少しだけ少ないが、その分細身で持ちやすい。
底面がわずかに膨らんでいて安定する。
蓋のロックが独特で、開けにくい人もいるかも知れない。勢いよく開くが角度がつけられていて飲みやすい。
飲み口は一体化されていて掃除しやすく、簡易な空気弁がついている。
ボディはコーティングされているようだ。塗装は今のところはげてないが、時間が経ってないのでまだ不明。
なお、たまたまかも知れないけど買ったばかりは妙な匂いがあってなかなか取れなかった。

前回のエントリでnamespaceに起因すると勘違いした不具合。
capistranoのmultistageでdeploy_toにstageごとに異なるパスを指定すると変になるという話。

multistageを使っている時に、config/deploy/staging.rbに以下のように書いたとする。

が、これは期待した動作をしない。deploy:symlinkの時にオーバーライドしたはずのdeploy_toが復活する。もしdeploy.rbでdeploy_toを指定していなければ、デフォルトの/u/apps/#{application}が使われる。

これを回避するには、staging.rbに以下を追加する必要がある。

これならdeploy_toが呼び出された時点で評価される。

しかし、全てのrails_envについて(staging.rb,production.rbなど)同じ内容を書かないといけないのでよろしくない。
ぱっと見だと難しそうなので、ゆっくりソースを追って考えてみます。

先日のエントリは色々間違ってました。

まず、Rails3.2でDBに接続しに行く問題はapplication.rbにconfig.assets.initialize_on_precompile = falseを追加することで回避できるみたい。RailsGuidesくらいちゃんと読めって話ですよね。このへんは先日の勉強会で教えて貰いました。


あとdeploy.rbでnamespaceを定義して更新時だけprecompileするコードだけど、multistageを使っているとパスがデフォルトになってしまったりでうまく動作しない。(multistageしてない時には正常動作するはず)
こちらはちょっと考え直す必要がありそう。うまく行ったらまた紹介します。

上記、別の問題とごっちゃになってました。そのままのコードで問題なしです。