MySQLでBLOB/TEXT型カラムにインデックスを張る

/ db

MySQL で新たにテーブルを作ったり、プライマリキー、ユニーク制約、またはインデックスを作成する際、下記のようなエラーが発生することがあります。

ERROR 1170 (42000): BLOB/TEXT column 'text_field' used in key specification without a key length 

結論として回避策から書くと、BLOB型またはTEXT型の場合は、インデックス作成時にキー長を明示してあげる必要があります。

create index new_index on table_name(text_field(100));

このエラーは、MySQL が BLOB型もしくはTEXT型 (これらに順ずる TINYTEXT型 や LONGTEXT型を含む)のような可変長カラムでは、その先頭から最大255文字分しかインデックスできないという制約から来ているようです。解決策は上記のとおり、キー長を明示するか、変わりに255以下で VARCHAR(100) のようなカラムを使って、そちらをインデックスとして使うといった工夫が考えられます。

考えてみれば当然と言える話ではあります。

題目を索引することはあれど、本文を索引した書籍など見たことがないですし、そこに意味がないことは誰もが分かるでしょう。たとえ本文を索引にするとしても、冒頭の一節というのが関の山。この MySQL の仕様は、理に適っている気がします。逆に本文を索引したい、つまり全文検索用の FULLTEXT インデックスであれば、TEXT型カラムにもちろん作成することができます。

このエラーに遭遇したときは、上記のような解決法もひとつの手ではありますが、そもそも TEXT型カラムを主キーにしたり、インデックスを張ろうという設計が正しいかどうかを考えてみた方が良いでしょう。

例外は、百人一首的に冒頭の一節から引きたいか、50音順インデックスを使うようなケースだけじゃないでしょうか。LIKE 検索で、先頭数文字で引っかけたい場合。それも、通常は最低1000 レコードを超えてこないとインデックスが効いてこなかったりするので、さらにレアケースな気がします。

エラーが起きるとついつい今すぐで回避方法を探してしまいがちですが、そもそもエラーになるような設計が正しいかどうか考えるクセは付けておきたいもんです。結局、そういう考え方が未来の自分を救ったりするんだから。


perl で配列に要素が含まれているか調べる方法

ある配列に特定の要素が含まれているかどうか知りたいとき、 java では List#contains が用意されていますが、どうやら perl では標準で用意されていないんですね。ここら辺を自前で書くのが perl 流といったところでしょうか。

#!/usr/bin/perl -l

my @array = qw/a b c d e f g/; undef %tmp; for (@array) { $tmp{$_} = 1; }
print $tmp{"a"} ? 'true' : 'false'; print $tmp{"h"} ? 'true' : 'false';

数値配列で有無をチェックする場合は、vec を使う方法で軽くできるとのこと。

perl で mkdir -p

perl で mkdir -p 同様のことをするには、File::Path の mkpath を使うと良いらしい。

#!/usr/bin/perl -w

use strict; use warnings; use File::Path;
my @dir = mkpath ('/data/test/1/2/3/'); for (@dir) { print $_ . "\n"; }

実行結果は、作成したディレクトリパスの配列。以下は、/data/test が存在していた場合の結果。

/data/test/1
/data/test/1/2
/data/test/1/2/3

ラクチンです。危なく自分でループ回すところでした。

なかなか便利なモジュールのノウハウが蓄積されないので、やりたいことがあったら、まずはモジュールを探してみる癖を付けるようにしたいなあ。perl ってサクサク書けるので、ちょっとした処理だったら自前でサブルーチン用意してしまっているんですが、本当はもったいないですよね...。

学習ベースの防備録として今後モジュール関連ネタ、メモしていきます。

mysql のスレーブを再構築する

/ db

レプリケーションができていないのでログを見てみたら、「Client requested master to start replication from impossible position」というエラーが出力されていた。確かに、「show slave status」で表示されるポジションが、バイナリログ内に見つからない...。

不整合の度合いがハンパないのと、運用から切り離されているサーバだったので、スレーブをゼロから再構築することにした。以下、そのときの手順メモ。

まず、マスターの更新を止めてデータをdumpします。

mysql> FLUSH TABLES WITH READ LOCK;

スレーブ開始にそなえてポジションを確認。

mysql> SHOW MASTER STATUS \G
         File: db01-bin.010
     Position: 5432
 Binlog_Do_DB: db_name
Binlog_Ignore: 
1 row in set (0.00 sec)

データをdumpします。

$ mysqldump -uroot -hdb01 db_name > /tmp/db_name.dump

マスターの更新ロックを解除。

mysql> UNLOCK TABLES;

マスター側の操作はここまで。続いて、スレーブの再構築の作業に入ります。最初に、これまでのレプリ情報を削除してしまいます。

# /etc/rc.d/init.d/mysqld stop
# rm /var/lib/mysql/master.info
# rm /var/lib/mysql/relay-log.info
# /etc/rc.d/init.d/mysqld start

データベースをゼロから作るため、今までのデータベースを削除して作り直し。

mysql> DROP DATABASE db_name;
mysql> CREATE DATABASE db_name;

マスターのdumpデータをリストア。

# scp db01:/tmp/db_name.dump /tmp/
# mysql -uroot -hdb01 db_name < /tmp/db_name.dump

レプリケーションの設定を最新のものに。ポジションとログファイルは、先ほど「SHOW MASTER STATUS」した結果のものを使用します。

mysql> STOP SLAVE;
mysql> CHANGE MASTER TO 
  MASTER_HOST='db01',
  MASTER_USER='repl',
  MASTER_PASSWORD='password',
  MASTER_LOG_FILE='db01-bin.010',
  MASTER_LOG_POS=5432;

スレーブを開始します。

mysql> START SLAVE;

これでレプリケーションが正常に行われるはずです。「SHOW SLAVE STATUS」やログにエラーなど発生していないことを確認しましょう。うまくいかない場合は、しかるべきときに mysqld のプロセスがきちんと停止していなかったとか、dump がうまくいっていなかったとか、そういったところだと思います。手順が少ないので、問題になる場所も限られます。

ここまで書いて気付いたのですが、スレーブが複数ある場合は、何もマスターの更新を止めてやる必要がないですね。そして、もっとシンプルな手順でできそう。

お疲れさまでした。

vim で開発するときに知らないと損する小技

転職を機に perl を書くようになって以来、vim 一本で開発のすべてを行っています。

かつては、何と java を vi で書いていたこともあったし、運用でしばしば vi を使う機会があったので、基本的な操作は身に付いていたんですが、本格的に vi を使うようになって色々と便利な技があることを知ったのでシェアメモ。

まずは、文字コード変換。

:e ++enc=shift_jis
:e ++enc=iso-2022-jp
:e ++enc=euc_jp

これができないと、そもそも vim 一本で開発することができないという話。テンプレ編集やメール系の開発するときに便利すぐる。

続いて画面分割

:sp

これで画面が上下に分割して編集できます。画面を切り替える場合は、Ctrl+w を2回。プログラムを書いていて、「あ、これって他はどうしてるんだっけ?」と思って一時的に参照したい場合に便利です。

現在カーソルのある画面を閉じる場合は、

:close

現在カーソルのある画面以外をすべて閉じて、通常モードに戻す場合は、

:only

diff のように行単位で違いを眺めながら編集したい場合は、

Ctrl+w → v

これで垂直分割になります。純粋に 2ファイルの diff を見るのならば、vimdiff で OK なんですが。

分割したそれぞれの画面で別のファイルを表示するには、その画面に切り替えて、

:e ファイル名

これで、新しいファイルの編集モードに入れます。

ファイルを開くという意味では、編集中のファイルにあるパスにカーソルを合わせて

gf

これで、そのパスにあるファイルを開くことができます。これ、ヤバイです。芋づる式にプログラムを編集できます。grep 結果をファイルにリダイレクトしておいて、あとで開いて順番に見ていきながら編集する場合に重宝しました。


画面分割は、「screen 使えば良いんじゃないの?」という話もありますが、ちょっとした比較には vim の画面分割はダントツに力を発揮します。特に、ノートPCやサーバのコンソールのように、小さい画面で頑張らないといけない時なんかは、知っていると知らないとでは作業効率に雲泥の差が出ますよ、ホントに。

ということで便利技をいくつか書いてきましたが、要するに「java × eclipse の開発は便利で良かったなぁ」ということです。 vim でどんなに頑張っても、さすがにアレにはかなわないですね。

MySQLのレプリ遅延の原因を調べる方法

/ db

MySQLのレプリ遅延の原因には、大きく分けて、転送遅延とSQL実行遅延の2つがあります。

転送遅延は、マスタでバイナリログに出力されたSQLクエリが、スレーブのリレーログに出力されていないケース。SQL実行遅延は、SQLクエリがリレーログに出力されたが、実行が遅れているケース。レプリ遅延時の問題の切り分けとして、まずどちらのケースに該当しているかを判断する必要があります。

転送遅延の判定方法

マスタでの SHOW MASTER STATUS の結果と、対象スレーブでの SHOW SLAVE STATUS の結果を比較します。比較する項目は、以下のとおり。

比較元(MASTER)比較先(SLAVE)説明
FileMaster_Log_File読取対象のバイナリログファイルの比較
PositionRead_Master_Log_Pos読取完了した位置の比較

この2項目で差がある場合、転送遅延が起こっている。マスタとスレーブのサーバ間に何らかの問題が起こっていると考えられるので、その線で本質的な問題を追っていくことになります。

SQL実行遅延の判定方法

転送に遅延がなかった場合、こちらの調査に移ります。

対象スレーブでの SHOW SLAVE STATUS から、次の項目同士を比較して判断します。

比較元比較先説明
Master_Log_FileRelay_Master_Log_FileSQLスレッドが最後に実行したバイナリログ
Read_Master_Log_PosExec_Master_Log_Pos読取完了と実行完了の位置比較

スレーブ側における、I/OスレッドとSQLスレッドの処理差から、つまりSQLの実行処理がどのくらい遅れているのかを調べることができます。SQL実行遅延の場合、スレーブの負荷が何らかの理由で高まっているケースなどが考えられます。マスタに比べてスレーブサーバの処理性能が劣るような場合、更新クエリが詰まることも考えられます。結構、厄介な話。

SQL実行遅延の場合、ほっときゃ直るケースも多かったりするのですが、転送遅延の場合は抜本的な対策が求められることが多いような気がします。両者とも各環境に応じたノウハウの積み上げから、最終判断をする必要はありますが。

ちなみに、そもそもの話として、レプリ遅延を監視するには、SHOW SLAVE STATUS のSeconds_Behind_Master という項目を見る方法が手っ取りばやいです。ただ、MySQL4.1.1以降から対応らしいので、MySQL4.0系では、こちらで紹介されているような方法は良いですね。

SHOW MASTER STATUS 、SHOW SLAVE STATUS で見られる項目の説明については、本家が一番わかりやすいと思います。

良いレプリ運用ライフを!

iモード2.0に見るドコモ様の不敵な態度

cookie や javascript に対応したことで話題の iモードブラウザ2.0 ですが、一方で搭載機種が次々に発売停止や発売延期になっているようです。

「docomo PRIME series N-06A」の一時販売停止及び「docomo STYLE series N-08A」の販売延期のお知らせ
「docomo PRIME series P-07A」の一時販売停止のお知らせ

伝え聞いたところでは、月末発売予定だった SH-06A と F-09A も販売延期になる模様。

発売日に販売停止という異例の事態が、さらにここまで拡大してくると、「あいかわらずN社のデスマ品質はハンパねぇなあー」とか、笑えなくなってくる。SH あたりが本当に販売延期となると、いよいよドコモ側の仕様の問題という見方が強まるんじゃないでしょうか。いずれの機種でも、同じ脆弱性が見つかっていると聞きますし。

そもそもこの問題自体、発売後にコンテンツプロバイダーからの脆弱性の指摘を受けて発覚したもの。(実際、ユーザーからの問い合わせなどは今のところなし)にもかかわらず、ドコモからコンテンツプロバイダー側に一切の説明はなし。いくつかの公式サイトに聞いたところでは、詳細情報は下りてきていないそう。

ドコモ様の不敵っぷりは、相変わらずです。

正直これだけのバージョンアップなので、今回問題となっている脆弱性だけで終わるとは思えず、今後ひきつづき見つかっていくでしょう。そこを共に乗り越えていくべきコンテンツ・プロバイダーとの距離感は、iモード2.0 普及の必要条件だと思うんですが。

機能的には可能性があると思っている iモード2.0 なので、ぜひキャリアとコンテンツプロバイダーが連携しながら、迅速な普及を行っていって欲しいですね。

iモードブラウザ2.0の衝撃

docomoより、かねて噂になっていた iモードブラウザ2.0 の仕様が発表されました。

iPhone や BlackBerry 、そして Android 携帯といったスマートフォン群の躍進を、iモードも黙って見ているわけはなかった。スマートフォン・ブラウザに対抗すべく、かゆいところに手が届く機能性を備えた、エポック・メイキングなアップデート。コンテンツ・プロバイダーへの衝撃は大きいですね。

作ろうiモード:iモードブラウザ2.0新機能一覧

新機能の詳細は、上記のドコモ公式サイトをご覧いただくとして、いくつか重要な機能をピックアップしていきます。

FLVとWMA 動画対応

Flash Video と Windows Media ファイルに対応。FLVのプログレッシブダウンロード、WMのストリーミング配信で最大10MBまで再生可能。これまで工夫をこらした配信で盛り上がってきた携帯動画の世界も、これで一気に敷居が低くなって裾野が広がりそう。

Ajax 対応

JavaScript に対応というのが機能の本質。しかし、XMLHttpRequest も使用可能で、広がりは無限大の機能拡張のため、あえて「Ajax 対応」と銘打ちました。

実際にどのくらい従来の Javascript と互換性があるかまでは未検証ですが、ECMA-262 3rd に準拠しているなら、prototype や jquery といったライブラリも、そのまま使えるかもしれません。(ブラウザキャッシュが500KBまでなので、必要部分のみに圧縮する必要はありそう)

Cookie 対応

これが一番びっくりした新機能。

RFC 2965 準拠の最小実装で、PCブラウザよりも制限は厳しめですが、セッション管理などを行うなら十分な仕様を満たしています。そう、ついにクッキーを使ったセッション管理ができる!

アクセス解析、視聴率測定、行動ターゲティングなど、幅広い展開が期待できるところ。

今回の対応で、ようやくdocomoでもリファラーの取得ができるようになったことを踏まえ、このあたりは非常に活発化するんじゃないでしょうか。正確な解析ができるようになって ROI を明確にできるようになれば、不況で伸び悩んでいると言われるアフィリエイト、純広枠への出稿の増加や、SEO / SEM への投資を誘導できるかも。モバイル市場拡大につながる可能性から、この cookie 対応には驚かせられました。エポック・メイキング。


さて、今後おそらく他社のブラウザもこの機能性に追従し、上回ってくることを考えれば、PCウェブと携帯ウェブの垣根がほとんど無くなる瞬間というのも、そう遠い未来の話ではなくなるのかもしれないなーと感じています。もちろんその間には、先に挙げたスマートフォンとの競争もあるし、コンテンツプロバイダーの盛衰もあって、にわかには想像しがたい話ですが、「iモード、次の10年」という括りでは夢物語ではないはず。そうなったとき、果たして強いのはPCポータル群か、モバイルコンテンツプロバイダーか、それとも。

一方、現在に目を移せば、これだけの機能追加が、果たして市場にスムーズに浸透するのかという懸念がありますね。iモードブラウザ1.0 をバージョンアップできるわけではない以上、2.0 対応にどれだけのコストを割いていくかの判断を、コンテンツプロバイダーは迫られるわけで。

そんな折に、こんなニュース。

「docomo PRIME series N-06A」の一時販売停止及び「docomo STYLE series N-08A」の販売延期のお知らせ

ブラウザに脆弱性があったということらしいですが、Javascript と cookie に対応したら、そういったセキュリティ面での問題がナーバスでしょう。セキュリティ対応という、コンテンツプロバイダーに求められる技術レベルが高くなれば、それも 2.0 対応コンテンツ普及への足かせとなりうるわけです。この販売停止騒動で、衝撃をくらったコンテンツプロバイダーも多かったんじゃないでしょうか?


だらだら書いてきましたが、Android 携帯をふくめ、今年夏以降のモバイル市場の変化には敏感でありたいですね。面白くなりそうです。(その前に、某バンクが夏を超えられるかという噂も聞きますが...)

perl でビット演算の結果を数値比較する際の注意点

ハマったのでメモ。

perl で、ビット演算の計算結果と数値を比較する判定文を書いたら、これがうまくいかない。書いたのは、次のようなコード。

if ($var & 1 == 0) {
	print $var;
}

$var の値が 1 だろうが 0 だろうが、とにかく結果は 0 となって $var が出力されない。これだけシンプルだと逆に原因が特定できずに困る。

答えは、「Perl の演算子と優先順位」にありました。要するに、比較演算子の方が、ビット演算子より先に評価されたため、常に演算結果が 0 となっていたのでした。これは盲点。

ということで、以下のように修正して解決。

if (($var & 1) == 0) {
	print $var;
}

このことは、特段 perl に限った話ではなくて、php でも同様だったし、java にいたってはコンパイルエラーになってしまった。(eclipse では、エラーに対して、親切に「小括弧内にビット演算命令を入れます」というヒントまで出てきた)

ビット演算は便利なのでよく使ってしまうんですが、評価順を意識しておかないと、思わぬバグが出てしまうことになるので、要注意ですね。

movable type 4.2 にしました

ブログを再構築しました。

2年以上、特にブログそのものに手をつけることなく、エントリばかり書いてきたのだけど、さすがに退屈になってきた。デザインも変えたいし、スパム対策もしたいし、機能性も上げたいし、ということで
思い切って大幅変更しました。

movable type

movable type のバージョンを、3.2 から 4.2 にアップグレードしました。本家の記事「Movable Type 3.x から Movable Type 4 へのアップグレード 」にしたがって進めて、特にはまるところもなく移行は終了。

ただ、そのまま移行してしまったので、テンプレート構成はMT3のときのまま。MT4らしくモジュールテンプレートをうまく使えば、カスタマイズ性が高まるのだろうけど、それは今後の課題。

MySQL

せっかく movable type をごっそり変えるので、合わせて MySQL も 4.0 から 5.2 にバージョンアップしました。主に性能面での改善を期待して。

が、しかし。

データの移行時に文字化けして、大ハマリしました。文字コードの関係で、単純に mysqldump した結果をリストアするのではいけないらしい。MySQL5 側の文字コードを latin1 に対応するように設定を変えて、なんとか乗り切った。ううう。

ちなみに本題の性能面については、ちょっとスピードアップした気がするけど、MT4 になった影響のような気もするので、まだまだ様子見。

デザイン変更

横幅をトータル 1000px にしました。

が、普段ビジネスで使用しているノート(1024×768)で見たら横スクロールが出て見づらかったので、実質 960px までスリム化しました。制作で使っている Macbook Pro だと、横が1920px もあるので感覚にぶる。危険きわまりない。今後、気をつけよう。

はてなブックマーク

はてなブックマーク API を使って、注目エントリーと人気エントリーをフッターに出力するようにしました。あと、各記事にブックマークしていただいたユーザ数と、ブックマーク用のアイコンも追加しました。自分もはてなユーザーで、他の人のブログで同様の機能があって便利だなーと感じていたので、そのまま自分も実装しました。

最近、また perl をちょいちょい書き始めたので、はてな API を使った遊びは、これからもやったりやらなかったりするかも。

広告効果検証

広告スペースを増やしたので、ウザイと思いますが、広告タイプごとの CTR などの数字をとりたかったのでお許しを。

今後、Adsense 以外の広告も掲載するかもしれません。すんません。「俺はRSSで読んでるから、別に...」という方も、そのうちRSS広告を差し込むかもしれないので、ごめんなさい。興味があるときは、クリックしてください。


とまあ、大幅リニューアルとなりました。

週末に一気にやったんですが、まだ設定が完了していないところや、移行ミスしていて、みっともないところもあるかもしれません。その際は、ちょっと我慢してください。早々に片付けますので。

そんなわけで、引き続き deftrash をよろしくおねがいいたします。

転職しました

だいぶ事後報告になりますが、前職を2月末で辞めて、3月から新しい会社に勤務しています。

受託開発のアーキテクトやプロマネ、コンサルといったところから、モバイルサービス系エンジニアにシフトです。畑違いも良いところで、今まで蓄積してきたノウハウが活用できなさすぎワロタ状態。ノウハウの持ち腐れはもったいないのと、自分の備忘録として、前職で会得したワザは、テキトーにここに投下していこうと思います。

エンジニアではあるわけですが、新しいビジネスのスキームを生み出し、利益を創出すべく動いていこうと思っています。技術バカに陥らないように。

coLinuxで複数環境を作る

自宅の開発環境の見直しをしていたのだけど、ようやくそれっぽくなってきた。

これまでは自作マシンをメインに、サーバとストレージという個人環境としては大げさな構成だった。新環境は、Macbook Pro が1台。色校用に外付けモニターは用意しているけど、基本はこの1台で、デザインもプログラムも資料作成も全部できるって算段です。すっごいシンプル。

Macbook Pro に Bootcamp で Windows を動かして、そこに coLinux をいくつか入れて開発用サーバに使っています。何か間違っている気がするけど、結構イケてます、マジで。VMWareより格段に快適です。

で、coLinux で複数の環境を用意する際のネットワーク設定にハマったので備忘録。

続きを読む "coLinuxで複数環境を作る"

MySQLで実行中のSQLをキャンセルする

/ db

誤って、巨大なテーブルの全レコードを対象にするようなクエリを投げてしまって、いつまで経っても計算結果が返ってこないことってあるじゃないですか。そんなときの話。

mysql> show processlist;
+----+------+---------------+------+---------+------+-------+------------------+
| Id | User | Host          | db   | Command | Time | State | Info             |
+----+------+---------------+------+---------+------+-------+------------------+
|  9 | root | localhost     | NULL | Query   |    0 | NULL  | show processlist |
| 10 | root | localhost     | NULL | Sleep   |    1 |       | NULL             |
+----+------+---------------+------+---------+------+-------+------------------+
2 rows in set (0.00 sec)

processlist では、現在実行中のスレッドを一覧表示することができる。1列目の Id はスレッドID。時間のかかっているSQLがあれば、Info にそのクエリが表示されるはずなので、その Id を調べて Kill すれば、スレッドを強制終了することができる。

mysql> kill 10;

ターミナルコンソールから Ctrl+C でキャンセルしたつもりになっていたのに、ロードアベレージがぐんぐん伸びていって焦って、ようやくこの方法を知ることになったのは、ここだけの秘密。

ほら、PostgreSQL だと Ctrl+C でクエリはキャンセルできるし、接続はプロセスで見れるから、mysql ビギナーの自分はこの挙動に驚きました、という話です。メモメモ。

javascriptで簡単に経過ミリ秒を取得する方法

javascript で日付をミリ秒に変換したい場合、

var date = new Date();
alert(date.getTime());
// 1235619446796

とするのが一般的だと思うのだけど、jquery を見ていたら、すっごいシンプルなやり方が書いてあった。

alert(+new Date());
// 1235619446796

日付インスタンスの頭に「+」を付けるだけ!日付オブジェクトは、四則演算するときに自動的にミリ秒変換して数値として計算するようだ。なるほど、うまいところを突いたなあ。さっすが jquery だ。

ちなみに「+」を取ると、単に Date#toString() の結果が出力されます。

alert(new Date());
// Thu Feb 26 12:38:04 UTC+0900 2009

でも、こうして書いてよくよく考えると、getTime() でも、そんなに面倒じゃない気がしてきた。すごく面倒くさがり屋さんにはオススメです!

IFRAME では src 属性を必ず指定した方が良いわけ

SSL環境で、IFRAME の src 属性に値がない場合、IE6 では下記の警告メッセージが表示されてしまう。なんか、このメッセージには以前も困らされた気がするなあ。

このページにはセキュリティで保護されている項目と保護されていない項目が含まれています。保護されていない項目を表示しますか?

...と言われましても、保護されていない項目を埋め込んだ記憶が無いのですが。

解決策は、本丸に書いてありました。

<!-- iframe id="layer"></iframe -->
<iframe src="/?scid=dummy.htm" id="layer"></iframe>

何でも良いから、src を書いておけば大丈夫なようです。そもそもこの施策だって、IEのバグに対応するために...ごにょごにょ。

それにしても、自分は初めて遭遇したんだけれども、本丸にあるってことは結構有名な問題なんだろうか。助かりました。


最新エントリー
MySQLでBLOB/TEXT型カラムにインデックスを張る
perl で配列に要素が含まれているか調べる方法
perl で mkdir -p
mysql のスレーブを再構築する
vim で開発するときに知らないと損する小技
MySQLのレプリ遅延の原因を調べる方法
iモード2.0に見るドコモ様の不敵な態度
iモードブラウザ2.0の衝撃
perl でビット演算の結果を数値比較する際の注意点
movable type 4.2 にしました
あわせて読みたいブログパーツ