DB設計の話

今の仕事ではこんな設計でテーブルが作られてる



ID
有効ID
品名
値段

まぁこれは単純な例だけど。


どういう使われ方をするかというと、IDがプライマリで、
有効IDと言うフィールドで、その項目が有効か無効かを判断するという作り。


で、有効IDはIDと同じ値が格納されていて無効だった場合はNULL値で表現されるという寸法。



設計の有効性はちょっと自分の知識では判断が付かないのだけど、PGとして「さぁSQLを作れ」と
仕事を振られると、この設計はヘタレPGにはちょっと困ってしまう。



何が困るかって、有効無効を判断する条件に、


[ 有効ID IS NOT NULL ]


ってのが紛れ込む可能性が非常に高い点だ。
単に、このテーブルから有効だけ、無効だけの商品だけを検索する場合は、特に制約がなければ誰だってそうする筈だ。だよね?

SELECT * FROM 商品 WHERE 有効ID IS NOT NULL
SELECT * FROM 商品 WHERE 有効ID IS NULL

けど、ここに曲者が2コ潜んでいる。


まずNULL値はINDEXが基本は使えない。
ビットマップ索引ならOKとか、DB2なら大丈夫とかあったりするらしいけど、ここではとりあえず駄目としておく。


次にNOT条件。言わずもがなでINDEXが使えない。確か。


こんなテーブル構成で、かつそのテーブルが莫大なデカさだと、件数が増えれば増えるほどネックになってしまう。
現に、今引き継いだシステムが遅い原因は、上記の構成にウン百万の件数が入ったヤバテーブルが全部ボトルネックだ。
使うSQL、使うSQLすべてがテーブルスキャン。よく使う機能が2分くらい戻ってこないとか完全に終わっている。




有効無効を表すのが 「1か0」 で表現される様なフィールドだったら索引使えるのにな・・・・
と何時も思いながら日々仕事をしている。この設計って何が有効なんだろう。誰かわかる人に聞いてみたい。






と、これ書いてる途中で

SELECT * FROM 商品
WHERE 有効ID <= (SELECT MAX(ID) FROM 商品 ) AND 有効ID >= (SELECT MIN(ID) FROM 商品 )

と書いたら索引読みできるなとか思いついた。
テーブルスキャン1回と、インデックススキャン3回のどっちが早いだろうか?
件数が多かったら絶対後者の筈だ。明日、会社で試してみよう。
(しかし、無効キーの抽出は IS NULL しか無いかな。上の方法でもどこかでNOTが出てきそうだし。無効の抽出だけは結局はビットマップ索引か。)



けど、ここまでしないとパフォーマンスが出せないこの設計にはやはり疑問を感じてしまうwww