給与計算などのシステム項目の特性の関係で第三正規化で設計することが多いです。
一人分のデータを構成する要素がやたらと多くなるのが特徴です
名前/個人IDなどの社員マスター的なマスタ項目
本給/通勤手当/家族手当などの加給項目...これは個人個人で異なるので0項目からn項目必要です。
組合費/健康保険/住民税などの控除項目...これも個人個人で異なります。
(社会保険などもあるのですが割愛)
加えてヤヤコシイのは家族手当や組合費といった項目は不定項目でテーブルで項目としてきめ打ちすると応用が利かなくなります。
つまりタイトルも個人個人異なるわけです。第三正規化で最小の単位に分解してデータを保持するのがDB上都合が良いわけです。
(*) (DBでも List( of dictioary(title,Money) ) のinstanceが使えればもう少し楽になるかもしれません)
第三正規化したときに問題になるのがパフォーマンスです。
非正規化する時に遅い時には第二正規化に戻すこともありますがそれは、DBの世界でSQL文(ストアード)で書いても遅い場合です。(これも割愛)
さて上記の給与の例です。、
aさんの場合の加給項目10項目,控除項目12項目あるとします。
関連Tableの引用は 社員マスター1レコード
加給項目.項目.10レコード
加給項目.金額.10レコード
控除項目.項目.12レコード
控除項目.金額.12レコード
最低, 1+10+10+ 12+12 = 45 レコードを引用して初めて Aさんのデータが作られるわけです。
SQL1文で極端な例として書くと
select Fld1,fld2....
from 社員マスター M
left outer join 加給項目マスター KT on M.code = KT.Code and KT.NO=1
left outer join 加給項目マスター KT on M.code = KT.Code and KT.NO=2からn
left outer join 加給金額マスター KT on M.code = KT.Code and KT.NO=1
left outer join 加給金額マスター KT on M.code = KT.Code and KT.NO=2からn
left outer join 控除項目マスター KT on M.code = KT.Code and KT.NO=1
left outer join 控除金額マスター KT on M.code = KT.Code and KT.NO=2からn
(left outer join句が45回続く)
となります。(実際はもっと工夫するわけですが)
この処理をSQL文で処理しないで、C#/VBなどのクライアント言語で処理すると 45回IOが発生することになり、処理が遅くなります。
ところが、業務要件を説明して製造の細部を指示しなければ、昔のISAM見たいにC#(VB)の中で45回ループするプログラムが上がって来たりします。
速度コストの差はかなりでます。
VBのソースを見ると
dim sql as string = ""
sql +=" select fld1,fld2........."
sql +=" from 社員マスター where cd ='" + ID + "'"
// 社員マスター引用
....
sql = "select 加給1 ... from 加給マスタ where id ='" + ID + "'"
//加給マスター20回繰返し
...
sql = "select 控除1 ... from 控除マスタ where id ='" + ID + "'"
//控除マスター20回繰返し
...
となっている。クラクラしてきた。自分で遅くなるソースを書いておいて、IO回数が多いので処理が遅いのは当然ですと仰られる。
(最低でも where id='" + ID + "'" と書かずに where id=@id と書いて欲しい。SQLインジェクションすら意識されていない。パラメータクエリの便利さが判ってのかな。)
(一部の)PMさん、SEさん...実装技術を知らないと処理の遅い低品質プログラムの非を見抜けませんよ。品質問題で顧客から睨まれるのはご自分ですよ。
(一部の)PGさん、 outer joinをいくつ繋げても DBはきちんと処理してくれるし、SQL(ストアード)を活用することを理解してね。