まだ重たいCMSをお使いですか?
毎秒1000リクエスト を捌く超高速CMS「adiary

2006/06/10(土)プログラムの実行速度と形式美

またもデータベースカラム追加

adiary ては、各ユーザーあたり3つのテーブルを使用しています。

  1. 日記本文のテーブル
  2. コメントのテーブル
  3. トラックバックのテーブル

従来から、日記本文のデータの中に、その日記に付いたコメント数やトラックバック数というデータを持たせていました。データベースの正規化の立場からすると、やってはいけないことなのですが、アクセスの度にいちいちSQLで集計とってたら遅くてかなわないということで。

今ではそれを逆に利用して、コメント数やトラックバック数が0のときは、そもそもコメントやトラックバックをロードするSQLを発行しないようにしています。

さらに一歩進めて。今回、コメントの一覧やトラックバックの一覧を機能をつける際*1、コメントごとに元記事のタイトルやら日付やらを引っ張ってくるようにしました*2。ですが、たかだか元記事の「日付」と「タイトル」だけを取得するために、コメント1件につき1回SQLを発行するのはなんとも効率が悪すぎる。

今回の変更で、コメントテーブル、トラックバックテーブル双方に元記事の「日付」と「タイトル」を保存するようにしました。せっかく正規化されているデータを分散させるなんて「なんてことだ!」とか言われそうですし、不整合が起こらないように管理するのが面倒ですが、背(形式美)に腹(処理速度)は代えられません

実はadiaryには、処理速度や見通しのために、プログラムの重複記述*3を敢えて行っている箇所が何カ所かあります。

*1 : 最近のコメント、最近のトラックバックでも同様に使用しています

*2 : つまり、コメントが参照している日記キー(diary_pkey)から日記本文をjoin……なのですが、擬似データベースも使えるようにする都合上、データベースではjoinせずにプログラム側でjoin相当の処理をしていました

*3 : ルーチン化可能だけど敢えて行っていない

よくみるプログラムたち

1.一本道プログラム

要求された処理を満たすようにだけ書かれた、能率も形式美も何もない「のっぺり」としたプログラム。いわゆる「プログラムを書ける人」の7割ぐらいが*4、こういうプログラムを書きます。

必要な処理が順列組み合わせで、なんの抽象化も、構造モデリングもなされずに記述され、大抵の場合はメンテ不可能なまでに*5巨大化し、下手をしたら1/3のソース量で同じ処理が書けるんじゃないか? と思えるものです。

2.形式美プログラム

機能ごとにソースが分離され、処理はきれいなまでに抽象化され、またはクラス化(オブジェクト指向)が徹底されて、非常に美しいプログラム。である反面、メモリの多重確保やメモリ間コピーなどは意図にも介さない。

事務系のプログラムやミッションクリティカルなプログラム(たとえば銀行システムや金銭を扱うような通販システム)では能率なんて求めず安全第一で書くべきだけど、処理速度や処理効率が(極端に)求められるプログラムである場合はときとして失格*6。頭の良い人がプログラムを教科書的に学んだ際に陥りやすい。

3.効率主義プログラム

自分はこのタイプ。限られたリソースや有限な資源を用いて、または計算量がNPであるような大問題を効率よく求めたときなどに書くプログラム。一見するとタイプ1の「一本道プログラム」と似て映るが、きちんと眺めれば効率を求めたものか、何も考えずに書きつづったものかは一目瞭然。

また、形式美をある程度理解した人間が書いた効率主義プログラムと、そうではない効率主義プログラムではメンテ性という意味で大きな差が出てくる。実行効率は形式美とある程度両立可能であるが、たまに調子に乗って必要以上に高効率を求め*7無駄にソースが見づらくなることもある(T-T

4.adiaryは?

  1. perlがあればどこでも動くという汎用性
  2. 抽象化され、差し替え可能な構成と形式美
  3. それでいて限定された環境でも高速に動くこと(cgi動作 & pure perl)
  4. 恵まれた環境ではさらに高速に動くこと(mod_perl2 or SpeedyCGI)

の優先度で作成されています。

*4 : とくにプログラムを学んだのではなくプログラムを教えてもらった人間に多い

*5 : メンテするぐらいなら最初から書き直した方がよっぽど速いし

*6 : 美しく書けば雑然と書くよりは普通に速いので、よっぽど速度重視な場面以外ではあまり構わない

*7 : ワンパスしか処理しないような場所で不必要な最適化をするとか

2006/06/09(金)6/9版スナップショット

  • 日記/コメント/トラックバックの一覧機能を付けました(削除などはまだです)。
  • 新着機能(コメント/トラックバック)を搭載しました。
  • タイトル画像およびショートカットアイコン(Favicon)を指定できるようになりました。
  • 標準パーサーに画像記法のプラグインを追加しました。
  • 標準パーサーに一時的なセクションアンカーなどを置き換える機能を追加しました。
  • その他細かい修正&機能アップ

そろそろβ版リリースできそうです(笑*1

*1 : 来週ぐらい……かなぁ

2006/06/08(木)一時的なセクション記号の置き換え

一時的なセクション記号の置き換え

その記事だけで、セクション記号などを置き換える方法です。例えばサブセクション記号を

::subsection_anchor=♥
**サブセクション

とすると、

サブセクション

となります。記事中のどこに書いても、その記事において最後の設定が有効になることに注意してください。

置換可能なものには以下のものがあります。

変数名内容
section_anchorセクションアンカー
subsection_anchorサブセクションアンカー
asidAmazonアソシエイトID
anchor_name_baseアンカー名のベース(先頭)
http_targethttp記法のリンクtarget(全体指定)
image_target画像によるリンク時のtarget(全体指定)
timestamp_format見出し時刻記法の時計フォーマット

2006/06/08(木)画像タグプラグイン

この項目は難易度高めです

画像記法の説明

画像記法は特定の場所においてある「画像へのリンク」を簡易にするためのものです。タグを使用することで、画像置き場が移動しても、汎用的に対応することができます。

まずユーザー定義タグを用いてタグを指定します。オプション(通常文字コードを指定する部分)に image と書くのがポイントです。

myimg       = 画像, image, 1, http://image.xxx.jp/image/$1_small.jpg
myimg#large = 画像, image, 1, http://image.xxx.jp/image/$1_large.jpg
myimg#link  = 画像, image, 1, http://image.xxx.jp/image/$1.jpg

のように指定します。最初は通常の表示画像、myimg#largeには大きな画像指定時の表示画像、#linkにはリンク先アドレスをそれぞれ指定します。受け取る引数の数は、すべて同じに設定してください。

この状態で、myimgタグは次のように置き換わります。

[myimg:test]
[myimg:test:large]
[myimg:test:たいとる]
[myimg:test:w50:たいとる]

ならば

<a href="http://image.xxx.jp/image/test.jpg" class="myimg">
<img alt="test" title="test" src="http://image.xxx.jp/image/test_small.jpg"></a>

<a href="http://image.xxx.jp/image/test.jpg" class="myimg">
<img alt="test" title="test" src="http://image.xxx.jp/image/test_large.jpg"></a>

<a href="http://image.xxx.jp/image/test.jpg" class="myimg">
<img alt="てすと" title="てすと" src="http://image.xxx.jp/image/test_small.jpg"></a>

<a href="http://image.xxx.jp/image/test.jpg" class="myimg">
<img alt="てすと" title="てすと" src="http://image.xxx.jp/image/test_small.jpg" width="50"></a>

よく分からないので

かえでさんの日記をサンプルにやってみましょう。

まず次のようにタグを定義します。

kimg       = album, image, 1, http://fait.abk.nu/blog/album/top/2006/06/.thumb/$1.jpg
kimg#link  = album, image, 1, http://fait.abk.nu/blog/album/top/2006/06/$1
kimg#large = album, image, 1, http://fait.abk.nu/blog/album/top/2006/06/$1

この状態で、[kimg:adiary1.jpg:かえでのアルバムの画像]とすると、

かえでのアルバムの画像

となります。