はじめに
こんにちは。小川です。
以前から気になっていた「SQLアンチパターン」という本を読みました。
とても良い本で今まで気づかずにやっていたことがSQLアンチパターンなんだと知ることができました。
勉強になったので、学んだことを言語化して量が多いのでいくつかの記事に分けて紹介していこうと思います。
今回は第Ⅱ部のDB物理設計のアンチパターンについて記載します。
この記事は「SQLアンチパターン」の気づき(DB論理設計3)の続きになります。
9章.ラウンディングエラー(丸め誤差)
アンチパターン
小数値のデータが必要な場合に、FLOAT型を設定するアンチパターンです。
デメリット
- 丸目誤差が生じてしまう
SQLのFLOAT型では「IEEE754標準」という規格に従って、実数を2進数形式でエンコードされます。
浮動小数点数を2進数形式で表現するため、無限精度が必要な値は「丸め誤差」が生じてしまいます。
解決策:NUMERICデータ型を使う
FLOATや類似したデータ型の代わりに、SQLデータ型のNUMERICまたはDECIMALを用いて、固定制度の小数点を表すようにする。
10章.サーティワンフレーバー(31のフレーバー)
アンチパターン
限定する値を列定義で指定するアンチパターンです。
例)
CREATE TABLE Bugs (
--他の列...
status CHECK (status IN ('NEW', 'IN PROGRESS', 'FIXED')
);
例のように列にはCHECK制約を定義できます。制約条件がFALSEになるような値の挿入や変更を拒否します。
他にもENUM型の定義、ドメインやユーザー定義型を使って列に入力する値を特定のどれかに限定する方法もあります。
デメリット
1.どんなデータが入っているのかわかりずらい
→status列に現在許可されている列挙値を取得するのに以下のSQLを実行する
SELECT DISTINCT status FROM Bugs;
現時点のすべてのバグステータスがNEWである場合、このクエリからではNEWしか返されない。
2.値の追加、変更、削除をする際に再定義する必要がある
3.移植が困難
→各種データベース製品間で列定義の仕様が統一されていないため移植が困難
解決策:限定する値をデータで指定する
今回の例だとBugsテーブルに紐づく、BugStatusテーブルを作成する。
CREATE TABLE BugStatus (
status VARCHA(20) PRIMARY KEY,
);
CREATE TABLE Bugs (
--他の列...
status VARCHA(20),
FOREIGN KEY (status) REFERENCES BugStatus(status)
ON UPDATE CASCADE
);
このようにBugsテーブルに行の挿入や更新を行うときは、BugStatusテーブルに存在するstatus値を使わなければならないようにできます。
まとめ
今回は第Ⅱ部のDB物理設計のアンチパターンについて一部まとめてみました。
この記事はこの本を読んで、私がこういう理解をしましたということを言語化してみました。
とても勉強になる本なので皆様もぜひ読んでみてください。
以上、小川でした。