データベースにおける、論理設計、物理設計、SQL設計、DBを用いたアプリケーション設計における、業務に起こりがちなシステム案件を例に、エンジニアが陥ってしまう本来のデータベース機能を活かせなくしてしまうアンチパターンを紹介してくれている。
開発現場での過去からの技術推移による積もり積もった負債による問題など逃れられず迫り来る重いものや、安易な先入観によって一気に深い奈落へと落とされる袋小路への罠など、システム開発における生きた現場感ある事例から解説を導入してくれているので非常に読みやすい。
データベースを利用した開発経験者、およびこれから開発を経験する人たちを対象に価値が出てくる著作だと感じた。
以下、内容メモ抜粋。
------------------------
1部 データベース論理設計のアンチパターン
■1章:ジェイウォーク:信号無視
多対多の関連を表現する交差テーブルの作成を避けるために、
属性内でカンマ区切りのリストを使うパターン
デメリット:
カンマ区切りのリストの値を使ってテーブル結合するのが手間
インデックスを使う機会も失われる
COUNT, SUM, AVGで細工が必要
リストへの追記方法の細工が必要
リストの区切り文字を含む文字列の挿入に注意が必要
varchar(30)などで定義した場合、リストが文字列数以内に収まるための制御が必要
リストのソート管理が複雑
解決策:
・交差テーブルを作成する。
多対多 → 1対多:多対1 とするためのクッションのためのテーブル
インデックスを活用できるようにある。
挿入されるIDなどの妥当性を、参照生合性などで保証させることができる。
>存在しているIDのみ登録させるようにする、など。
リストでないので、区切り文字を気にする必要なし
リストの長さ制限がある場合は、COUNT関数などで制限するようアプリ側で実装する
■2章:ナイーブツリー:素朴な木
親コメント、子コメントの対応ができるメッセージフォーラム掲示板の作成
親コメントIDをもたせたコメントテーブル
コメントの取得
>親子関係の階層が深いと、単一のSQLで取得するのが難しくなる。
>階層数だけテーブルを自己結合でjoinする必要あり
削除は、子孫特定に複数クエリが必要
サブツリー全体削除は、外部キーの整合性制約を満たすために、最下層から順番に子孫を削除する必要あり。
アンチパターンの見つけ方。
・ツリーの深さを考慮しなければならない
・解決策を講じても他の作業が犠牲になり難しくなる
・定期的に生合成を保つスクリプトでメンテが必要
解決策;代替ツリーモデル
・経路列挙モデル
属性pathに、親子関係階層を記載 1/, 1/2/, 1/4/6/7/ ...など
参照生合成を保証できず、冗長な情報を格納するという脆弱面がある。
・入れ子集合モデル
各ノードに nsleft, nsrightのポインタを持たす
ツリー構造の深さ優先順にノードをなぞってnsleft, nsrightに順に値を割り振る
参照生合成を保証できない。ツリーの変更より、検索のみの場合に有利
・閉包テーブルモデル
ツリーは、自分と自分以下のサブノード全てのリンクを持つ構造
>ルートは、全てのノード、サブノードは、サブノード以下の全てのノードの情報を持つ
コメントと、ツリー構造のテーブルを分けている。階層の計算が楽な分、多くのスペースが必要(それぞれが、自分のノード以下の全てのリンクを保有するため)
>コメントテーブルが別れているので、階層構造を削除してもコメントを定期技削除する必要がある。
■3章:IDリクワイアド(とりあえずID)
とりあえず主キーとしてID列を用意(サロゲートキーのような扱い)してしまうアンチパターン。
サロゲートキーを用意したが、本来は、bugIDとproductIDのそれぞれ多対多の組み合わせを表現する必要があるテーブルであった。そのままではbugIDとproductIDの値が重複する行を許してしまう。
そこで、bugIDとproductIDの複合ユニーク設定をすることにする。しかし、そうなっては主キーのID列の存在意義とはなんなのか。bugIDとproductIDの複合主キーでいいのではないかという話になる。
解決策:
・主キーはわかりやすい属性名にする。
・とりあえずIDではなく、自然キーと複合キーを活用する。
■4章:キーレスエントリ(外部キー嫌い)
ストレージエンジン自体がサポートしていない(例:MySQL:MyISAM 外部キー制約をサポートしていないストレージエンジン)場合もあるが、エンジニア自体が外部キーの設計を横着してしまうアンチパターン。
外部キー制約を使えないために、ユーザが無効なデータを入力した時に即座にエラーを返せない。品質管理用スクリプトという本来不要な処理も必要になってしまった。
解決策:外部キー制約を宣言する
メリット:
参照生合成:外部キー:親テーブルの主キーやユニークキー列に存在する値のみ許可する事ができる
参照制約にはカスケード更新削除処理が使える。アプリケーションコードでは真似できない。
foreign key(status) references BugStatus(status)
on update ascade
on delete set defaut
外部キー制約でオーバヘッドは発生しない。むしろメリットがある。
・挿入、更新、削除のさいに、チェック用SQL文が不要
・複数テーブル変更を防ぐためのテーブルロックが不要
・データ品質管理用スクリプトを独自で作って管理する必要なし
■5章:EAV(エンディティ・アトリビュート・バリュー)
日付ごとのカウント:日付でgroup化しcount(*)
しかし、日付が行によって異なる列に格納されているケースの問題
エンティティ・アトリビュート・バリュー(オープンスキーマ、スキーマレス、名前/値ペア)と呼ばれる。キー・バリュー方式とも?
・列数を減らせる
・新たな属性をサポートするのに列数を増やす必要なし
create table Issues(
issue_id SERIAL PRIMARY KEY
);
create table IssueAttributes(
issue_id BEIGINT UNSIGNED NUT NULL,
att_name VARCHAR(100) NOT NULL,
attr_value VARCHAR(!00),
PRIMARY KEY(issue_id, attr_name),
FOREING KEY(issue_id) REFERENCES issue(issue_id)
);
この場合、列値を取得するのが元来のSQLと比較して冗長になる。
select issue_id, data_reported from issues;
->
select issue_id, attr_values as date_reported
from IssueAttrivutes
where attr_name = 'date_reported';
・一つのissueはissue_id,attr_nameにより複数行に別れ、行ごとに属性、属性値のペアが格納されているので、特定属性をNULLにできない。
・存在が必須の属性も、行で格納されているので制約で設定することができない。
・IssueAttributeの行ごとに、属性、属性値を管理しているため、列のSQLデータ型を選択
できない。
>個別のデータ型の列を追加すると、さらにクエリは複雑化してしまう。
・参照制約も使うことができない。>attr_value列が、全て参照制約の条件に合わないといけなくなる。
・属性名に一貫性がないケースが起こりうる、その時のSQLも複雑になる。
・同じissue_idの情報を一行の情報として取得したい場合、joinが属性数必要。
アンチパターンの見つけ方・
・メタデータの変更なしで拡張可能。実行時に新しい属性を定義できる
・導入時の初期設定が不要で裏でDBを使っているパッケージの多くはカスタマイズしやすいようにEAV設計を採用している
>非リレーショナルな管理なら、それらに特化したDBを使うべき
・BerkleyDB
・Cassandra
・CorchDB
・Hadoop/HBase
・MongoDB
・Redis
・Tokyo Cabinet
解決策:サブタイプのモデリングを行う
・シングレテーブル継承
関連するすべてのサブタイプを一つのテーブルに格納
・具象テーブル継承
サブタイプごとにテーブルを作成
・クラステーブル継承
継承を活用して、スーパータイプ、サブタイプを作成
・半構造化データ
サブタイプが多い場合や、頻繁に新しい属性を追加したい場合
LOB列を追加し、XML,JSONなどで属性名、属性値を共に格納する。
どうしても、EAVを使わざるを得ない場合。
>行の集合として取得する。
同じissue_idの複数行を、ループで取得し、オブジェクトのプロパティとして設定するPHPの例>p101
「メタデータは、メタデータのために用いましょう」
■6章:ポリモーフィック関連
複数の親テーブル参照をする問題
行ごとに異なるテーブルとjoinして結合することはできない。
解決策
・参照を逆にする
交差テーブルを作成
複数の親テーブルと、対象テーブルの多対多を表現するテーブルを、複数必要な親テーブルの数だけ作り関連づける。
・道を合流させる
unionを用いて結合する:列の数とデータ型が同じである場合のみ
・共通の親テーブルを作成
■7章:マルチカラムアトリビュート(複数列属性)
複数の値を持つ属性を格納する:1章のJAYWALKと同じテーマの問題
バグの特性情報として、複数タグをもたす>3つの属性で管理
・値の検索でタグを検索する場合は、3列すべて取得が必要になる。
一つのタグを検索するごとに、3つのorでの比較、またはin句の式が必要
・3つのタグで同じ値を格納したくない
しかしマルチカラムアトリビュート・アンチパターンでは、防ぐことができない。
>普通にinsert文で挿入できてしまう
アンチパターンを使用しても良い例:
3つのタグの列が、列ごとにタグを入力するロール(ユーザ、エンジニア、管理者)など目的が異なる場合。
解決策:従属テーブルを作成
バグIDとタグの多対多を表現できるテーブル
>空いているタグの列を探すことも不要で、削除、挿入が可能
■8章:メタデータトリブル(トリブル:大増殖)
年度ごとのデータ格納用列が、毎年追加される
>しかも、一部の顧客でしかデータが埋まらない、ほかはNULL
行数が多いより少ないテーブルのクエリ実行の方が速いという考えが、誤った考えを導く危険性。
・行数の多いテーブルを複数のテーブルに分割
>年度ごとにテーブを分ける
新たなテーブル作成管理が増える
日付などが異なった年度に入らないようにcheck制約をテーブルごとに設定を変えて作成
>日付などが、去年の情報の誤ったレコードを発見。しかし、行の更新だけだとcheck制約違反になってしまう。
・列を複数列に分割
分割されたテーブルだと、複数テーブル間の主キー、ユニーク列の一意性の保証ができ>ない。
主キー値を作るためだけにテーブルを新たに一つ定義が必要
複数テーブルをまたいだクエリにunionを使用
>メタデータ列の追加がある場合は、全テーブルで列を同期が必要
参照整合性の管理
年度ごとにテーブルが分割されているため、従属テーブルで外部キー定義ができない
>一つしか定義できないため
解決策:
・パーティショニングと正規化
水平パーティショニング(シャーディング)をつかう
行で分割。
行を分割するルールを決めて、物理的に分割。
物理分割されるが、一つのテーブルを扱うようにSQLステートメントを実行できる。
・垂直パーティショニング:列で分割
・従属テーブルの導入
マルチカラムアトリビュートの解決法と同じ
------------------------
2部 データベース物理設計のアンチパターン
■9章:ラインディングエラー(丸め誤差)
float型:実数を2進数形式でエンコードする
浮動小数点の特徴を理解する必要あり
>10進数で記述できる全てを2進数で格納できるわけでない>丸め誤差
無限小数となってしまうものは、有限小数による近似値となる
解決策:NUMERICデータ型を使用
NUMERIC, DECIMAL
■10章:サーティワンフレーバー
列値に規定の選択肢を複数指定する。
>check制約 in句でチェックするようにする
列のデータ型は ENUMが列挙で使用できる。
選択肢が増えるたびに、check制約、ドメイン、ユーザー定義型を扱うクエリは複雑化する
。プログラマはアプリコード側にも値のリストを定義してメンテナンスできるように設計したがる。
>双方の同期がずれたら大きな不具合になる。
選択肢の追加による構造変化には、ALTER TABLE句で既存の選択肢の値も列挙しなければな
らない。
>変更の際、テーブルへのアクセスをブロックし、テーブル内容をダンプし、テーブル再定義して、保存したデータを読み込まなければならない場合もある。
選択肢が廃止されたり、他に統合されたり、分割された場合、選択済みの値を参照しているレコードはどうすればいいのか。
解決策:限定する値をデータで指定する。
参照テーブルを作成し、許可する選択肢の値を一行に一つずつ格納する。
元のテーブルに外部キー制約を制限し、この参照テーブルを参照させる。
>参照テーブルの値の更新、挿入で、選択肢の編集が可能になる。
■11章:ファントムファイル(幻のファイル)
DBで画像ファイルパスを格納して、アプリで表示するのに使用していた。
>DBが物理クラッシュ
>画像ファイルの格納場所はDBサーバの/var以下
>DBのバックアップはあるが、/var以下は一時ファイルなのでバックアップはなし。
>復旧に大量の時間を浪費する事になる。
画像の格納方法
・blob型に入れる
・ファイルパスで管理
DBでレコードを削除しても、画像ファイル自体も消さない限り残る
ファイルを削除すると、すぐにファイルにアクセスできなくなる。
ファイル内容を変更すると、トランザクションがコミットされる前に、他のクライアントはその変更されたファイルを目にすることになる
>ロールバックの問題
ロールバックでレコードが回復されても、ファイルはロールバックの対象ではない。
SQLアクセス権は、外部ファイルには適用できない
SQLはファイルが存在することを検証できない。
解決策:blobで画像を管理する
データベースごとに以下のBLOBをサポート
・MySQL MEDIUMBLOB 16MB
・Oravle BLOB v9.2 4GB, v10.1 128TB
■12章:インデックスショットガン(闇雲インデックス)
・インデックスを全く定義しないか、少ししかインデックスを定義しない
・インデックスを多く定義しすぎるか、役に立たないインデックスを定義
・インデックスを活用しないクエリを実行
インデックスを定義すると、行の更新、挿入で、インデックスの構造も更新するためオーバヘッドが生まれる
>そのオーバヘッドをなくすためインデックスを排除する人がいる。
複合インデックスの勘違い
インデックス a,b
の場合、b,aでソートすると、インデックスを活用できない
解決策:MENTORの原則に基づいて効果的なインデックス管理を行う
M:Measure 測定 SQLの実行時間を測定
E:Espkain 解析 QEPの分析結果レポートからボトルネックを調査
N:Nominae 指名 インデックスを必要な箇所を特定
T:Test テスト クエリプロファイリングで確認
O:Optimize 最適化 キャッシュメモリのチューニング
R:Rebuild 再構築 定期メンテナンス:断片化対応など
-----------------------------------------------
3部:クエリのアンチパターン
■13章:フィア・オブ・ジ・アンノウン(恐怖のunknown)
NULLの表現
・無:null
・不明:unknown
・適用不能:inapplicable
アンチパターン:NULLを一般値として使う、または一般値をNULLとして使う
式でNULLを扱う
hours列がNULLの場合> select hours + 10 from bugsのselect 結果はNULL
不明(unknown)より10大きな値を持つ数は、ひき続き結果は不明(unknown)
検索において、nullは除外される
〜以外の検索においても、nullは対象外
特定したい場合h、IS NULL, IS NOT NULL で指定する
prepared statement でnullは使えない
れい:select * from bugs where assinged_to = ?(ここにnullを指定);
sum,avg関数なのでnullが入ると式が複雑になるので、
nullをなくし、値を-1などで表現
>しかし、-1などもsum,avg関数を混乱させてしまう
外部キー設定で、nullを-1表現した場合は、
参照がない(null)を表す-1の行を参照先テーブルで作らなければならない。
解決策:nullを一意的な値として使う
データ型を問わず、欠けている値にはnullを用いる
■14章:アンビギュアスグループ(曖昧なグループ)
GROUP BYと、集計関数による列表示のSQL文中に、集計化してないユニークのIDが格納されている列をSELECT句で指定してしまう。
>同一グループの集計範囲には複数のユニークIDが含まれるため、一つに絞れない。
>クエリがエラーになるか、不正確なデータが表示されてしまう
アンチパターンの見つけ方:
単一値の原則に反するクエリを作成すると、エラーメッセージが表示される
解決策:
・曖昧でない列を使用する。
関数従属性のある列のみにクエリを実行する。
・相関サブクエリを使用
サブクエリの結果がない場合は、外部クエリの結果が適用される
・導出テーブルを使用
・外部結合を使用する:ない項目にはNULLが入る
・他の列に対しても、集約関数を使用
■15章:ランダムセレクション
ランダム選択するクエリが、選択行数が増えることによる性能劣化
従来のソート:
インデックスを使用したランダムソート
列の値などでソートする。
非決定性をもつRAND関数などのソート:
select * from bugs order by rand() limit 1;
selsect * from bugs order by date_reported
インデックスからメリットを得られない。
テーブルスキャンによるソートとなる。
>小さなデータセットなら用いても良い
解決策;特定の順番に依存しない
・1から主キーの最大値までの値をランダムに選択する
・全てのキー値のリストをうけとり、ランダムに一つ選択する
・オフセットを用いた乱数(データセットの行数をカウントし、0と行数までの乱数)で選択する。
■16章:プアマンズ・サーチエンジン(貧者のサーチエンジン)
パターンマッチ述語を使用してしまう
%LIKE%
後方一致はインデックスを活用できない。
解決策:適切なツールを使用する
全文検索エンジンなどを利用すること
MySQL,Oracleなどのテキストインデックス
■17章:スパゲッティクエリ
複数抽出項目に対して、SQLクエリを一つにまとめる横着をしてしまう
複雑な問題をワンステップで解決しようとすてしまう。
>クエリにデカルト積が発生
デバッグなどの難易度が高くなる
解決策:分割統治を行う。
ワンステップずつ着実にSQL文を作成する。
■18章;インプリシットカラム(暗黙の列)
属性名が競合したりしてSQLクエリに影響を及ぼす、予期せぬテーブル間のカラムの問題
ワイルドカードの多用、暗黙列の多用
select文などで、列指定をワイルドカードで記述し列を省略する問題
>他の修正で、列が追加されたり、削除されたらどうなるか?
インサート時も、列名を省略する>暗黙列の問題
>インサート時には、全ての列を順番に値を指定しなければならない
解決策:
・列名を明示的に指定する。
必要な列だけを指定する。
-----------------------------------------
4部:アプリケーション開発のアンチパターン
■19章:リーダブルパスワード(読み取り可能パスワード)
パスワードを平文で格納してしまう。
>セキュリティリスク
IDとパスワードの比較
2つの条件をまとめない
>アカウントが問題なのか、パスワードが問題なのか問題を区別できない。
アカウント名のブルートフォース攻撃なのか同一アカウントのパスワードのブルートフォース攻撃なのか判断できない
パスワード再取得機能で、パスワードを平文で送信するのは深刻なセキュリティリスク
>暗号化、登録メールにリセットと新パスワード設定のページへの誘導すべき
解決策:
・ソルトをつけてパスワードでハッシュする
>網羅的なハッシュマップによる元データを紐付ける攻撃を阻止できるソルト
・SQLクエリでパスワードを平文で扱わない
■20章:SQLインジェクション
動的SQLの代入部分に脆弱が混入する
;(セミコロン)で区切って悪意のあるSQLの注入
select * from bugs where bug_id = [1234; delte from bugs]
'(クォート)などで、SQLを分割して悪意あるSQLの注入
$sql = "select * from projects where project_name = '$project_name'";
※$project_nameに'を含んで好きなSQLを注入できてしまう。
同じく動的SQL代入時に末尾にor〜などの付与
~where account_id = [123 OR TRUE]
対処法:
・値のエスケープ
後続文字のエスケープ:バックスラッシュ
・プリペアドステートメントの利用
クエリの前処理(プリペア)時にパラメータのプレースホルダーを文字列内に残す
そして、準備したクエリを実行する前にクエリパラメータとして値を渡す
>最も強力な防御手段
値のリストを一つのパラメータにできない
テーブル識別子もパラメータとして扱えない。(テーブルを指定できない)
列名もパラメータとして使用できない
SQL予約語もパラメータにならない
・ストアドプロシージャの活用
・データアクセスフレームワーク(ORMなど)の活用
解決策:
・入力のフィルタリング
・動的値のパラメータ化>プリペアドステートメント
・ユーザの入力をコードから隔離
■21章:シュードキー・ニートフリーク(擬似キー潔癖症)
番号に欠番がある場合、欠番を埋めようとしておこるアンチパターン
外部キー属性を持っている場合は、ON UPDATE CASCADEを設定していれば連鎖的に変更され
るが、ない場合は手動で調整が必要>サービス中断も視野に入れる必要あり
欠番3を埋める作業中に4から移行していたら、他作業で行追加されたさいには5移行の連番が入るため、3に移行後は、4が欠番となる・・・
違反などで取り消されたID番号を謝って再利用してしまう問題>業務支障が起こる
解決策:擬似キーの欠番は埋めない
■22章:シー・ノー・エビル(臭いものに蓋)
データベースの戻り値を無視してしまうアプリケーションコードの問題
アプリケーションに点在するSQLしか読まない問題
>例:コードの分割記述されているSQL部を連結するとスペースが埋まってしまっている
解決策:エラーから回復する処理にする
try~catch文
API戻り値の検証判定処理の追加
■23章:ディプロマティック・イミュニティ(外交特権)
通常のシステム開発における、ソースコード管理、設計ドキュメント管理、テスト確認コードやドキュメントにおけるベストプラクティスから、SQLの管理を除外してしまう。
>データベースを特別扱いしてしまう傾向がある問題
解決策:包括的に品質問題に取り組む
・文書化:ER図、テーブル設計、トリガ、ストアドプロシージャ、
・バージョン管理:DDLによる定義スクリプト、トリガ、プロスージャ、初期投入データ、
ER図やドキュメントのバージョン管理
・テスティング:自動化テストユニットコード
テーブル定義、制約、トリガ、ストアドプロシージャ、初期投入データ、クエリ、ORM
■24章:マジックビーンズ(魔法の豆)
MVCアーキテクチャにおけるM(モデル)が、アクティブレコードそのものであるパターン
>アクティブレコード:オブジェクトのフィールドとテーブル列のマッピングをサポートするパターンのこと
・アクティブレコードはモデルをデータベーススキーマに強く依存する
16テーブル>16のモデルが必要
テーブルの修正>モデルの修正必要>モデルを呼び出すコントローラも修正必要
・ドメインモデル貧血症
多くのコントローラから、必要となる全てのモデルに網の目のように関連が生まれてし>まう
>テスト確認の複雑さ、困難さが上がる
解決策:モデルがアクティブレコードを持つようにする
>model, daoの分離
■25章;砂の城
想定不足
・サービスの成長速度における想定性能の見積もり
・障害時の対応、ポリシーの策定
解決策:
・ベンチマークで事前性能測定
・テスト、検証環境の構築
・例外処理によるトレースの整備
・バックアップ
・高可用性設計
・ディザスタリカバリ
・運用ポリシ策定
----------------------------
5部:付録
■付録A:正規化のルール
ORDER BYがないと、予期せぬ順番を返す
列指定がないと、よきせぬ列順を返す
正規化すれば性能が上がるというわけではない
>データ不整合、冗長の排除、整合性制約の整備
第1〜6正規形(ボイスコッド、ドメインキー正規形含む)
解説
以上。
プライム無料体験をお試しいただけます
プライム無料体験で、この注文から無料配送特典をご利用いただけます。
非会員 | プライム会員 | |
---|---|---|
通常配送 | ¥410 - ¥450* | 無料 |
お急ぎ便 | ¥510 - ¥550 | |
お届け日時指定便 | ¥510 - ¥650 |
*Amazon.co.jp発送商品の注文額 ¥3,500以上は非会員も無料
無料体験はいつでもキャンセルできます。30日のプライム無料体験をぜひお試しください。
無料のKindleアプリをダウンロードして、スマートフォン、タブレット、またはコンピューターで今すぐKindle本を読むことができます。Kindleデバイスは必要ありません。
ウェブ版Kindleなら、お使いのブラウザですぐにお読みいただけます。
携帯電話のカメラを使用する - 以下のコードをスキャンし、Kindleアプリをダウンロードしてください。
何か問題が発生しました。後で再度リクエストしてください。
OK
SQLアンチパターン 大型本 – 2013/1/26
{"desktop_buybox_group_1":[{"displayPrice":"¥3,520","priceAmount":3520.00,"currencySymbol":"¥","integerValue":"3,520","decimalSeparator":null,"fractionalValue":null,"symbolPosition":"left","hasSpace":false,"showFractionalPartIfEmpty":true,"offerListingId":"Z5CbKj34ZtiVYDtLLgq%2FE9StMKARCBKResVqojgx8RlMZRIOKvOL%2F5hJJji1Fdc7GBuyVMBZ93FlbxolfbYqOJjuFhdu%2BvEJblVt%2BkdILtWXeJgEOlABLeoJj2BtBlWwihdtvtgapJU%3D","locale":"ja-JP","buyingOptionType":"NEW","aapiBuyingOptionIndex":0}, {"displayPrice":"¥2,828","priceAmount":2828.00,"currencySymbol":"¥","integerValue":"2,828","decimalSeparator":null,"fractionalValue":null,"symbolPosition":"left","hasSpace":false,"showFractionalPartIfEmpty":true,"offerListingId":"Z5CbKj34ZtiVYDtLLgq%2FE9StMKARCBKRgLaMK2KVQ68iBRKhNTvRIim%2B2Xrxbjq%2BJyvTDgFwmnQDRhZ6SyJ%2F3fZPgaGgCssESvqE9PUdLfz3ey6UTTl%2BHvDAA5sjMj%2F%2BqhkFx7Hbo2L3HcTxUsWTfmjaNkD5tMoKjLNhqWhPDiDC9YEKWDCz2JhhoGvhoYxH","locale":"ja-JP","buyingOptionType":"USED","aapiBuyingOptionIndex":1}]}
購入オプションとあわせ買い
本書はDB設計やSQL記述の際に避けるべき事柄を1章で1つ、25個紹介する書籍です。
リレーショナルデータベースを中心に据えたシステム開発には、様々な場面で陥りやすい失敗(アンチパターン)があります。
本書はデータベース論理設計、データベース物理設計、クエリの記述、アプリケーション開発という4つのカテゴリに分かれて、それぞれの分野におけるアンチパターンを紹介し、失敗を避けるためのより良い方法を紹介します。
複数の値を持つ属性や再帰的なツリー構造の格納から、小数値の丸めやNULLの扱いに起因する問題、全文検索やSQLインジェクション、MVCアーキテクチャなど、実践的かつ幅広いトピックを網羅します。
データベースに関わるすべてのエンジニア必携の一冊です。
リレーショナルデータベースを中心に据えたシステム開発には、様々な場面で陥りやすい失敗(アンチパターン)があります。
本書はデータベース論理設計、データベース物理設計、クエリの記述、アプリケーション開発という4つのカテゴリに分かれて、それぞれの分野におけるアンチパターンを紹介し、失敗を避けるためのより良い方法を紹介します。
複数の値を持つ属性や再帰的なツリー構造の格納から、小数値の丸めやNULLの扱いに起因する問題、全文検索やSQLインジェクション、MVCアーキテクチャなど、実践的かつ幅広いトピックを網羅します。
データベースに関わるすべてのエンジニア必携の一冊です。
- 本の長さ352ページ
- 言語日本語
- 出版社オライリージャパン
- 発売日2013/1/26
- 寸法3 x 19 x 24 cm
- ISBN-104873115892
- ISBN-13978-4873115894
よく一緒に購入されている商品
¥2,860¥2,860
最短で5月24日 金曜日のお届け予定です
在庫あり。
¥2,750¥2,750
最短で5月24日 金曜日のお届け予定です
在庫あり。
総額:
当社の価格を見るには、これら商品をカートに追加してください。
ポイントの合計:
pt
もう一度お試しください
追加されました
一緒に購入する商品を選択してください。
この商品をチェックした人はこんな商品もチェックしています
ページ 1 以下のうち 1 最初から観るページ 1 以下のうち 1
商品の説明
著者について
Bill Karwin(ビル・カーウィン):ソフトウェアエンジニアとして20 年以上の経験があり、アプリケーション、ライブラリ、サーバー(Zend Framework for PHP5、InterBaseリレーショナルデータベース、Enhydra Javaアプリケーションサーバーなど)の開発とサポートに携わってきた。キャリアを通じて、自らの知識を他のプログラマーと共有し、成功と生産性向上を支援してきた。数多くの質問に答えるなかで、最も問題を生じさせやすいSQLの典型的なミスについての独自の見解を得るに至った。
登録情報
- 出版社 : オライリージャパン (2013/1/26)
- 発売日 : 2013/1/26
- 言語 : 日本語
- 大型本 : 352ページ
- ISBN-10 : 4873115892
- ISBN-13 : 978-4873115894
- 寸法 : 3 x 19 x 24 cm
- Amazon 売れ筋ランキング: - 10,804位本 (本の売れ筋ランキングを見る)
- - 38位データベース (本)
- カスタマーレビュー:
著者について
著者をフォローして、新作のアップデートや改善されたおすすめを入手してください。
著者の本をもっと発見したり、よく似た著者を見つけたり、著者のブログを読んだりしましょう
-
トップレビュー
上位レビュー、対象国: 日本
レビューのフィルタリング中に問題が発生しました。後でもう一度試してください。
2020年3月31日に日本でレビュー済み
2021年5月21日に日本でレビュー済み
Amazonで購入
アンチパターンがなぜアンチパターンと呼ばれてるのか理解して、
アンチパターンが選択肢に上がった際に、メリットデメリットをあげられるようになることが大事。
アンチパターンが選択肢に上がった際に、メリットデメリットをあげられるようになることが大事。
2020年8月16日に日本でレビュー済み
Amazonで購入
本書はRDS設計における「よく言われる・聞いたことがある」けどみんなが踏み抜いている地雷を一通り書いてくれている。「SQLの書き方自体は理解したけど、結局どう使えば問題ないのかわからない」というレベルの層にドンピシャです。
この本では25章で25個の落とし穴を紹介してくれているが、そのうちの1個に引っかかった人はそのほかの価値がわかるのではないかなと思う。
章ごとに書いてるプロジェクト内要注意ワード(例:「SQLで複数の列を検索する方法は?」)のような不吉な匂いを感じたときや「あれ、これって確かまずい設計だったけどどうやって書けばいいんだっけ?」と疑問が湧いた時に該当の章を読み直すのに丁度良いです。
もっと早く知りたかったというレビューが多いが、その通りだと思う。
対象層ではない人と思う人へのコメント
【対初心者】
コマンドだのについて説明してくれている本ではないので、SQL自体の理解だったり単純なRDS環境の構築だとかで躓いているレベルの人には少し早い本です。
ただ、ほっとくと絶対どっかで引っかかることが書いてるので、理解できるようになったら早く学ぶべきことしか書いてないです。買っておいて、自分がわからないことがわかった頃に読んで下さい。
【対エキスパート】(私は上級者ではないので、見当違いかもしれません...)
本書の良いところはわかりやすく、初心者が必ずぶちぬくバッドケースをまとめてくれた点にあると思う。
逆にもっと専門的なモデリングの本などで設計を学んだ人にはあまりに初級的なことしか書いてないようには感じてしまうかもしれない...
でも、先輩がこの本で教えてくれたら私は嬉しいと思う。教えてほしかった。
この本では25章で25個の落とし穴を紹介してくれているが、そのうちの1個に引っかかった人はそのほかの価値がわかるのではないかなと思う。
章ごとに書いてるプロジェクト内要注意ワード(例:「SQLで複数の列を検索する方法は?」)のような不吉な匂いを感じたときや「あれ、これって確かまずい設計だったけどどうやって書けばいいんだっけ?」と疑問が湧いた時に該当の章を読み直すのに丁度良いです。
もっと早く知りたかったというレビューが多いが、その通りだと思う。
対象層ではない人と思う人へのコメント
【対初心者】
コマンドだのについて説明してくれている本ではないので、SQL自体の理解だったり単純なRDS環境の構築だとかで躓いているレベルの人には少し早い本です。
ただ、ほっとくと絶対どっかで引っかかることが書いてるので、理解できるようになったら早く学ぶべきことしか書いてないです。買っておいて、自分がわからないことがわかった頃に読んで下さい。
【対エキスパート】(私は上級者ではないので、見当違いかもしれません...)
本書の良いところはわかりやすく、初心者が必ずぶちぬくバッドケースをまとめてくれた点にあると思う。
逆にもっと専門的なモデリングの本などで設計を学んだ人にはあまりに初級的なことしか書いてないようには感じてしまうかもしれない...
でも、先輩がこの本で教えてくれたら私は嬉しいと思う。教えてほしかった。
2020年9月15日に日本でレビュー済み
Amazonで購入
DBの参考書を1つでも読んで、実務で新規プロジェクト、機能開発、または機能追加でDBのテーブルを考えたことある人なら、何となくアンチパターン(やってはいけないこと)が分かるかもしれない。
改めて言語化してくれている良い参考書だと思います。
この参考書は一通り読んで、何となく覚えて、DB設計時に読み返すレベルで良いと思います。
また、他人のレビューする際は、この参考書の記事をスクリーンショットを送り、指摘することにも使用できます。
この参考書を長くて読みたくない人は目次を見てアンチパターンを知ると良いです。
目次で気になった単語があり、理解したいなら、単語でGoogle検索すればヒットします。(ブログ等に書いてくれている人がいる。)
あまりにも検索する数が多いなら、購入して読むことをおススメします。
実務のDB設計でたまにアンチパターンを見たときは、「DBの参考書1冊くらい読んでそこそこ理解してないのかよ」と思う時があります。
最近はEAVに遭遇して、マジで保守しづらかった。
改めて言語化してくれている良い参考書だと思います。
この参考書は一通り読んで、何となく覚えて、DB設計時に読み返すレベルで良いと思います。
また、他人のレビューする際は、この参考書の記事をスクリーンショットを送り、指摘することにも使用できます。
この参考書を長くて読みたくない人は目次を見てアンチパターンを知ると良いです。
目次で気になった単語があり、理解したいなら、単語でGoogle検索すればヒットします。(ブログ等に書いてくれている人がいる。)
あまりにも検索する数が多いなら、購入して読むことをおススメします。
実務のDB設計でたまにアンチパターンを見たときは、「DBの参考書1冊くらい読んでそこそこ理解してないのかよ」と思う時があります。
最近はEAVに遭遇して、マジで保守しづらかった。
2020年12月13日に日本でレビュー済み
Amazonで購入
sqlの勉強のために買った。
2019年2月2日に日本でレビュー済み
Amazonで購入
現場でDBを利用したシステムに携わった後に読むのが良い。なので初心者よりも中級者向けの本。
現場で可動しているシステムがアンチパターンだからといって設計変更になるケースは多くない。特に規模の大きいシステムであればなおさら。なので、実務で得られた設計や手法の問題点を本書で復習し次に活かすのが最適だと感じた。
交差テーブルの利用を避けたいがためにカンマ区切りの値が入った属性を格納するのは、区切り文字やデータ型による格納上限があったりと拡張性が狭まる。正規化して交差テーブルを作成した方がインデックスも利用できるしメリットが多い。
キーワードなどの親子関係を持つテーブルの構成は入れ子集合や閉包テーブルなど有名な設計方法がある。システムの要件に合わせてメリット・デメリットを考慮して選択するのが良い。他の設計に比べて扱い易い閉包テーブルから検討して見るのも悪くない。
JOIN構文で結合条件で利用するカラム名が同じ場合USINGを使うと簡潔になる。ON構文が省略できるため。
auto incrementを利用しidという疑似キーを利用するのは良くある。主キーと疑似キーが混同して利用され煩雑になる可能性を孕んでいる。一部のフレームワークのように疑似キーを主キーとして利用するルールが統一されているのであれば良い。単にidという名ではなくテーブル名にちなんだカラム名を付けるのが良い。
親テーブルのレコードを削除したけど子テーブルのレコードは存在したままになり、検索結果の集計に不適切になるのは、外部キー制約が適切ではない。参照整合性を保つためにも、適切な外部キー制約を付ける。外部キー制約付与によって大きなオーバーヘッドになることはない。
RDBで名前/キーのペア専用の汎用的なテーブルは適さない。必須属性・外部キー制約が使えず参照整合性を維持できない。名前/キーのペアが増えるに従ってJOINの数が増えてSQLが肥大化する。STIや各テーブルに共通の項目をまとめた基底テーブルを利用するCTI、拡張性が高いが絞り込みやソートが難しくなるJSONの利用などを検討する。または、MongoなどのスキーマレスなDBを検討する。
レコード数が多いテーブルのパフォーマンス向上に水平・垂直パーティションが役立つ。
水平についてはシャーディングが有用。例えば、年毎にシャーディングしてレコードを分かりやすく分散。
垂直の場合はTEXTやBLOBで格納されている列を外に出すことを検討する。ワイルドカード(*)で検索が走るとTEXTやBLOBのカラムが参照され重くなる原因になる。
float型は数値が丸まるので、10億倍すると予期せぬ値が返ってくる場合がある。そのため、固定制度の小数点を定義できるnumeric型を使う。
ENUMやCHECK制約は値の種類が増えたり、削除が発生した際に既存のレコードへの対応だけでなく、スキーマの定義変更も必要になるので使う機会はほとんどない。
RAND関数をソート順をランダムにするのは、テーブルスキャンによるソートになり高コスト。また、ソートにインデックスの恩恵も得られない。RDB側でなくアプリケーション側で対応するのが現実的。
複雑なクエリを作成して1発で結果を取得するのは綺麗だが変更に弱い。細かく分解して結果を結合させた方が保守性は高い。
24章のアクティブレコードの話はフレームワーク利用者は一読しておくと参考になる。
モデルがDB操作を簡便にするアクティブレコードという機能を持っている。
フレームワークを利用しているとモデルは1つのテーブルに対するDB操作を担っているように見える。
しかしこれは適切ではなく、モデルはアクティブレコードの機能を持っていて、必要に応じたテーブルへの操作をするものという捉え方の方が適切。
コントローラー側で、次々とモデルを呼び出す処理がある場合は要注意。疎結合、高凝集性を考慮し、それらをまとめるモデルを作成するのが妥当。
現場で可動しているシステムがアンチパターンだからといって設計変更になるケースは多くない。特に規模の大きいシステムであればなおさら。なので、実務で得られた設計や手法の問題点を本書で復習し次に活かすのが最適だと感じた。
交差テーブルの利用を避けたいがためにカンマ区切りの値が入った属性を格納するのは、区切り文字やデータ型による格納上限があったりと拡張性が狭まる。正規化して交差テーブルを作成した方がインデックスも利用できるしメリットが多い。
キーワードなどの親子関係を持つテーブルの構成は入れ子集合や閉包テーブルなど有名な設計方法がある。システムの要件に合わせてメリット・デメリットを考慮して選択するのが良い。他の設計に比べて扱い易い閉包テーブルから検討して見るのも悪くない。
JOIN構文で結合条件で利用するカラム名が同じ場合USINGを使うと簡潔になる。ON構文が省略できるため。
auto incrementを利用しidという疑似キーを利用するのは良くある。主キーと疑似キーが混同して利用され煩雑になる可能性を孕んでいる。一部のフレームワークのように疑似キーを主キーとして利用するルールが統一されているのであれば良い。単にidという名ではなくテーブル名にちなんだカラム名を付けるのが良い。
親テーブルのレコードを削除したけど子テーブルのレコードは存在したままになり、検索結果の集計に不適切になるのは、外部キー制約が適切ではない。参照整合性を保つためにも、適切な外部キー制約を付ける。外部キー制約付与によって大きなオーバーヘッドになることはない。
RDBで名前/キーのペア専用の汎用的なテーブルは適さない。必須属性・外部キー制約が使えず参照整合性を維持できない。名前/キーのペアが増えるに従ってJOINの数が増えてSQLが肥大化する。STIや各テーブルに共通の項目をまとめた基底テーブルを利用するCTI、拡張性が高いが絞り込みやソートが難しくなるJSONの利用などを検討する。または、MongoなどのスキーマレスなDBを検討する。
レコード数が多いテーブルのパフォーマンス向上に水平・垂直パーティションが役立つ。
水平についてはシャーディングが有用。例えば、年毎にシャーディングしてレコードを分かりやすく分散。
垂直の場合はTEXTやBLOBで格納されている列を外に出すことを検討する。ワイルドカード(*)で検索が走るとTEXTやBLOBのカラムが参照され重くなる原因になる。
float型は数値が丸まるので、10億倍すると予期せぬ値が返ってくる場合がある。そのため、固定制度の小数点を定義できるnumeric型を使う。
ENUMやCHECK制約は値の種類が増えたり、削除が発生した際に既存のレコードへの対応だけでなく、スキーマの定義変更も必要になるので使う機会はほとんどない。
RAND関数をソート順をランダムにするのは、テーブルスキャンによるソートになり高コスト。また、ソートにインデックスの恩恵も得られない。RDB側でなくアプリケーション側で対応するのが現実的。
複雑なクエリを作成して1発で結果を取得するのは綺麗だが変更に弱い。細かく分解して結果を結合させた方が保守性は高い。
24章のアクティブレコードの話はフレームワーク利用者は一読しておくと参考になる。
モデルがDB操作を簡便にするアクティブレコードという機能を持っている。
フレームワークを利用しているとモデルは1つのテーブルに対するDB操作を担っているように見える。
しかしこれは適切ではなく、モデルはアクティブレコードの機能を持っていて、必要に応じたテーブルへの操作をするものという捉え方の方が適切。
コントローラー側で、次々とモデルを呼び出す処理がある場合は要注意。疎結合、高凝集性を考慮し、それらをまとめるモデルを作成するのが妥当。
2019年12月12日に日本でレビュー済み
Amazonで購入
翻訳がわかりやすく、読みやすかったです
内容も実際のコードを出しながらの解説のため、理解しやすかったです
付録としてついている正規化についての項目がとても良かったです
内容も実際のコードを出しながらの解説のため、理解しやすかったです
付録としてついている正規化についての項目がとても良かったです