SQLer 生島勘富 のブログ

RDB・SQLの話題を中心に情報発信をしています。

シビアな設計

 http://d.hatena.ne.jp/Sikushima/20110809
 http://d.hatena.ne.jp/Sikushima/20110810
 http://d.hatena.ne.jp/Sikushima/20110811

 の続きです。

 シビアな設計が要求されるということは、リソースのどこかにボトルネックが発生するということになります。

 ボトルネックの定義とは、ある時間帯でリソースの使用率が100%になるというポイントです。粗っぽく考えればリソースは

    CPU(は使用率)
    メモリー(は容量スワップ発生まで)
    ディスク(I/Oと容量)
    ネットワークトラフィック

 となります。

リソースのウェート

 システム個別に固有のボトルネックはあるのですが、
    CPU:メモリー:ハードディスク:トラフィック
で、何にウェートを置いて考えるかは、時代によってベーシックな考え方というのが変わっています。ちょっと歴史を振り返ってみましょう。
 

 ■ 昭和の設計
    ハードが非常に高価だった。
    どれもが高価で非力であったため、比率は
      CPU:メモリー:ハードディスク:トラフィック
        =1:1:1:1
    
  ● この時代の特徴
    汎用機の料金がCPUの使用時間で課金されるため、ケアレスミス
    コンパイルし直すなんて許されない時代。
    「割り算を極力使わない」などの規約もあった。
    (分からない人は50代以上の人に訊いてみて下さいきっと盛り上がる。)
    もちろん、JOINなんて考えられない。
    ディスクもメモリー天文学的に高価だったため、
    日付の年は2桁で保存していた(後のY2K問題)
    ネットワークは300〜1200bps(キロとかメガとかギガじゃない)ほどしかなかった。


 ■ 20世紀の設計
    CPUのウェートがムーアの法則で下がりだし、
    インターネットで外部に対するサービスもはじまる。
    LAN
      CPU:メモリー:ハードディスク:トラフィック
        =1:5:2:1
    WAN
      CPU:メモリー:ハードディスク:トラフィック
        =1:5:2:5

  ● この時代の特徴
    Y2K問題が顕在化する。
    昭和の設計から抜けきず、CPUのウェートが下がっていることに
    対応できない人も多い。
    COBOLからの過渡期で、COBOLの設計に引きずられることが多い。
    引きずられた結果、バッドノウハウを正しいと勘違いし蓄積
    している技術者が増えた。
    Y2Kで一儲け(苦笑)


 ■ 21世紀の設計
    CPUのウェートが一段と下がった。
    ハードディスクは I/O の問題は以前としてあるものの、
    容量は無限と考えてよくなった。
    扱うデータ量が爆発的に増えた。
      CPU:メモリー:ハードディスク:トラフィック
        =1:10:2:5

  ● この時代の特徴
    皆さんで想像して下さい。

昭和の遺物

 40代の私でも、コンパイル回数など全く気にしない世代ですが、私より上の世代では、コンパイル前に机上デバッグを行うのが当たり前。昭和の設計では CPU を使う処理を嫌う傾向が、今に比べると非常に強くありました。COBOL は基本的にシーケンシャルにデータを保存しているため JOIN は非常に遅く CPU を使う処理になるため、やってはいけない処理とされていたのです。

 そのため、パフォーマンスが要求される処理では非正規化が当たり前で、非効率にデータを持つ分、僅かでも容量を節約するため日付は6桁で持つことがほぼ無条件に行われていました。

 二十数年の時間が流れて、コンパイル回数や日付6桁のように、既に絶滅した常識や感覚もありますが、なくならない感覚もあります。その最たるものは CPU が気になって仕方がない人の感覚でしょう。リソースモニターでチェックし易いからか、上司が気にするからかのいずれかが原因と思いますが、CPU のウェートが高いままの人が大勢いる。

 冷静に分析すれば「JOINをすればサーバに負荷が掛かる」と感じる(検証してないハズ)のは、データがシーケンシャルに保存されていた昭和の設計イメージを引きずったままということです。つまり、成功事例(失敗事例)は簡単に引き継がれ、文化になれば未検証で信じてしまいますから、二十数年に亘り引き継がれてしまいます。現実に、私よりはるかに若い、もしかしたら平成生まれの人達にも、昭和の設計の残滓が引き継がれてしまっているわけです。

 本当に文化というのは思考停止を生む怖いものです。

処理を分解してリソースの負荷を検討

 データベースサーバの負荷は要素毎に分解し、それぞれのリソースに対する影響を考えます。更に、工数やパフォーマンス、保守性も加味して検討するのが上流の設計です。

 では、代表的なものを分解して考えてみましょう。

 ■JOINする/しない

SQLを受け取った回数 CPU
トラフィックに影響
JOINした方が少ない
データブロックを読んだ回数 ディスクI/O
モリーに影響
同じ
ソート回数 CPU
モリーに影響
同じ
モリー使用量×使用時間モリーに影響 JOINした方が少ない
データ転送量 トラフィックに影響 JOINした方が少ない
パフォーマンス 品質に影響 JOINした方が良い
工数 価格・納期に影響 技量による
保守性 将来の費用に影響 技量による

 ■正規化/非正規化(売上ヘッダ・明細で、ほぼ1ヘッダ、1明細のとき)

SQLを受け取った回数 CPU
トラフィックに影響
同じ
データブロックを読んだ回数 ディスクI/O
モリーに影響
非正規化の方が良い
ソート回数 CPU
モリーに影響
ほぼ同じ、非正規化の方が若干良いかも
モリー使用量×使用時間モリーに影響 ほぼ同じ、正規化の方が若干良いかも
データ転送量 トラフィックに影響 同じ
パフォーマンス 品質に影響 非正規化の方が良い
工数 価格・納期に影響 非正規化の方が若干良い
保守性 将来の費用に影響 正規化の方が良い

 ■正規化/非正規化(売上ヘッダ・明細で、1ヘッダ、複数明細が多いとき)

SQLを受け取った回数 CPU
トラフィックに影響
同じ
データブロックを読んだ回数 ディスクI/O
モリーに影響
正規化の方が良い
ソート回数 CPU
モリーに影響
ほぼ同じ、非正規化の方が若干良いかも
モリー使用量×使用時間モリーに影響 正規化の方が良い
データ転送量 トラフィックに影響 同じ
パフォーマンス 品質に影響 正規化の方が良い
工数 価格・納期に影響 非正規化の方が若干良い
保守性 将来の費用に影響 正規化の方が良い


 JOINするしないでは、トレードオフの関係は、すべてのリソースに対して技術者の技量しかありません。

 しかし、正規化/非正規化では大きなトレードオフはありませんが、データの状況によってメモリーとディスクI/Oの負荷が違います。

 システムによっても状況は違いますが、現在では、メモリーとディスクI/Oの方がほとんどのシステムでウェートが高いため、1つのヘッダに平均して数行以上の明細が付くときには正規化すべきです。逆に、売上ヘッダ・明細が、ほぼ1:1でつながり複数明細になることはまれ、というシステムでは非正規化した方が効率的になります。しかし、余程シビアなシステムでない限り、トレードオフになっても「保守性」を重視して正規化することが多いでしょう。


 また、桁数の多い備考欄などのカラムが必要なプログラムが少ないときには、分割した方が多くのプログラムでデータの読み込み量が減るため効率的です。

 しかし、備考欄を別テーブルにすると、技量にかかわらず備考欄を使うプログラムで開発工数・管理工数も増えます。

何とトレードオフするか

 技術者の技量以外にトレードオフの関係があるときには、技術的に答えは1つではない。正規化がいいか、非正規化がいいかなんて、技術的にはどちらとも言えないのです。しかし、技術者の技量しかトレードオフの関係がないときには、技術的な答えは1つです。

 政治的な判断は分かりませんが、技術的な答えが1つになるときは、技術的一般論としては議論は不要で、そこにしつこく絡まれると私は罵倒します。「それでも技術者か?」ってね。

 私はシステムの全体設計から、詳細設計、一つのSQLを書くにあたっても、頭の中で粗くリソース単位に負荷を分けて考えています。
 実際には、APサーバ、クライアントまで含めて、同時起動されるプログラムはどうか、JavaScriptにふるか、Ajaxを使うか、APサーバにやらせるか、DBサーバにやらせるか、技術者の技量はどうか。というところまで考えますから、どうでもいいところでは横着することはもちろんあるけれど、なぜ、こういう形になっているか常に理由があります。(「横着した」も理由の1つ)

 人によってウェートの付け方は様々でしょう。そこには個性や状況判断が入る所で、昔のイメージを引きずることも、好き嫌いもあるでしょう。私のウェートの付け方は、技術者の技量と CPU をかなり低いウェートで見積もります。一方、政治を重要視する人は、技術者の技量を第一に考えるかも知れません。

 それを間違いとは言いません。どちらも正しいし、どちらも間違っているでしょう。

 しかし、技術的に考えれば、技術者の技量にウェートを置くと「技術的には間違っているけれど敢えて選ぶ」ということが増えます。

 そのときに「技術的には間違っている」と意識して欲しいのです。

 でないと、本当にシビアな設計は出来ないし、Y2K問題のように簡単には引き返せない間違いが文化として定着してしまいます。実際に私が罵倒するような内容というのは、昭和から引き継いでしまったバッドノウハウで、それを更に将来に引き継いでどうするのか。なんとかして私の世代で断ち切りたいと努力してきたわけです。

 残念なことに「データベースサーバで処理した方がデータベースサーバの負荷が下がります」ということが直感的におかしいと感じる人に、私はよくぶつかり全否定されます。現実問題として、そういう人は上流に多い(ほぼ全員か?)し、説明(お説教)には最低でも小一時間掛かります。上流がその小一時間の苦痛に耐えれることはまずないし、理解できたとしても、過去の自分がやってきたことを全否定することになりますから、簡単には受け入れられないでしょう。

 ですから、政治的に私が勝てることはない。これは残念ながら事実です。


 しかし、次の世代には、ちゃんと技術的に議論できる環境になって欲しいと願っています。若いくせにいつまでも「昭和の設計思想」を振りかざすものじゃないです。


 悪いけれど、シビアなシステムだからこそ、「JOIN禁止」「固定長カラム」「集計関数禁止」いずれも、目的のデータベースサーバの負荷を下げることにも、工数にもパフォーマンスにも、全く逆の効果になっている。技術者の技量を考えて政治的に正しくても、技術的に議論の余地はないのです。それに、シビアになればなるほど技術者の教育に力を入れるべきでしょう。生半可な技術でシビアなシステムに挑むなんて、本当に危険だと私は思うのだけれど、政治の世界は魑魅魍魎ですな〜。

 どうでもいいけれど、私は大きい方から見ていきます(ただし、政治を除く)。大きい方から見ていけば技術的には SQL で出来ることは SQL でするべきとなり、その後のAPサーバでどんな言語を使うかとか、あまつさえどんなフレームワークを使うといった問題は、極めて小さいどうでもよい問題なのです。誤差の範囲でよく絡まれるけどそんなちっこいこと知らんがな。

 イライラしているときは「ですます調」を止めて書くことが多いのですが、実際には書きにくく、読みにくくなってしまって(苦笑)意味がないので「ですます調」に戻します。(所々で崩れてきたらイライラしているということでご了承を……)