それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

フラグと not null の変換

データベースにフラグを持たせるとき、いつも迷います。そのフラグほんとうに必要か?と自問しています。既読とか未読とか、削除とか有効とかフラグがいっぱいついてるテーブルを作らないように心がけています。

データベースは3値とおぼえます

データベースは3値とおぼえておくと捗ります。データベースには値が3つあります。

true / false / null 

全部のテーブルのカラムに not null が書かれててたりしてアレ・・・

is null / is not null の利用

case 使えばいいと思うんですよ・

select (
        case 
            when read_date is null then true 
            else false 
        ) as is_read 
from user_rss_entry;

みたいな感じ。

null / not null も case 句で true false に置き換えてあげれば、十分に使えると思うんですよ。

RDBMSによっては、null / not null はインデックス的に不利かもしれないけどね・・・

以下は個人的見解です。

フラグよりは、意味のある数字を入れればいいと思います。

既読フラグよりは、読んだ日付。
削除フラグよりは、削除日付
削除フラグよりは、削除した管理人名

など、意味のある値を入れればいいと思います。
これらも十分に使えると思うんですよ。

is null は検索速度遅いじゃん

SQL的にはそうですね。null は b-tree には乗りそうにないので遅そうです。
でも、同じ意味で

select * from table where gender != 2

などの 否定や

select * from table 
where updated between "2013-03-21" and "2013-03-25"
;

だってインデックス使われないといえますよね。true/faseだと はインデックスに効果薄いですからね。

まぁ、細い実装はRDBMSに依って違いますが、、、

ただしNULLインデックスは実装依存

mysql の場合はちゃんとインデックスされてるようですよ。

col_name IS NULLを使用した検索では、col_nameにインデックスが張られている場合にインデックスが使用されます。

http://dev.mysql.com/doc/refman/5.1/ja/mysql-indexes.html


is null でもちゃんと インデックス使われるんですね。便利です。

追記

MySQLの場合、インデックスは比較的優秀だった記憶があります

=, >, >=、<, <=あるいはBETWEEN演算子を使用する表現のカラム比較に、B-treeインデックスが使用可能です。
LIKE がワイルドカードキャラクタで始まらない定数文字列の場合、インデックスはLIKE比較にも使用できます


でもさ。テーブル中のフラグに大量にインデックスあるのどう考えてもアレ。
今まで見た中で最高に困ったのはチェックボックスがすべてboolean で大量入ってたユーザーテーブル。。。まぁO/Rマッパを使うにはそうなんですけど。
検索遅いといって、そのテーブルに大量の無駄インデックスを貼りまくってて、「インデックスは貼れば貼るほど早くなるので!貼りまくれ」と言われたときは、その会社、次の日から行かなくなりました。
遅いのは、その大量インデックスのUPDATEが遅いんだよ・・・って。カラム数の順列組み合わせに近いけインデックスがあった。

2値(男女)のカラムにインデックスとかなんの意味があってつけてるんですかねアレは。

追記2

削除フラグは遅い。削除フラグは削除フラグがたったデータが大量になってくると、遅いし、メンテ不便だしで正直好きじゃない
削除データ専用のテーブルに移してしまいたい。。。

MySQL では利用可能な場合でもインデックスが使用されない場合があることに注意してください。この一例として、インデックスの使用によって、MySQL がテーブルの 30% を超えるレコードにアクセスする必要が生じる場合が挙げられます

http://dev.mysql.com/doc/refman/5.1/ja/mysql-indexes.html

とあるように削除フラグがある場合でも30%以上のレコードにアクセスすると遅いです。
慎重にクエリ作る必要があり面倒。うっかり削除フラグを除いた検索がサブクエリやJOINに含まれてたりしてパフォーマンス劣化するとおもいます。

NULL否定されても構わないけど、意味のないフラグカラムに入ったり、そこにインデックスを貼るよりは意味のあるデータがある方が僕は好きです。

そもそも、MySQLにbooleanカラムは無いわけですし。。。