「危険な兆候5つのポイント」と題して、ものものさんが、ブログを書いているのですが。。。以下の5行しかないんです。
・create view
・order by
・join(使っていない)
・if nest
・null
おお、これは、なんか、ゲームで、地図とか、アイテムをもらった心境っすね。
このメモの推理を1つ。たぶん、これは、「RDBでの」危険な兆候かなあ。。。
はじめの、
・create view
・order by
・join(使っていない)
この3つは、佐藤正美氏のセミナーで聞いたことがある。
佐藤氏は、View禁止、Group Byをするから遅くなるといっている。
理由は、これらの処理をRDBで行った場合、ワークテーブル(転置テーブルだったかな?)領域を確保するから。
この領域確保=広大なメモリ確保をするから遅くなるといっていたと思います。たしか。
ちなみに、メモリ確保をすると遅くなるというのは、RDBだけでなく、VC++なんかでもそうで、CStringをやると、文字列領域をとって遅くなったり、ファイル領域をいっぺんに読み込もうとして、領域確保しようとすると、遅くなったりする。
エヴァンゲリオンのような、組み込み系ロボット(なのかなあ?)だと、この遅れは、こまるので(シトにやっつけられてしまうので)、どうも、エヴァの場合、1バイトずつ読み込んで処理しているらしいことが、番組中、「intのc」という言葉から推測されるというのは、以前のブログに書いた。
で、VIEWを禁止するということは、JOINしろということになるので、1番目と3番目は同じことになる。
しかし、単純にJOINをしたら、遅くなるだろう。
そこで、佐藤氏は、JOINをしやすくするために、徹底的な正規化と、その正規化したものに、バンバンIndexをはって、JOINはindexで解決するような形を提唱している。
しかし、注意していただきたいのは、この手法では、JOINは早くなっても、indexを多用するので、更新や挿入は遅くなる問題がある。
つーことで、実務上は、程度問題だと思う。
氏の提案は、確かに画期的で、その発想はいいとおもうが、全プロジェクトで常に従うべきかどうかは、自己責任ということで、自分で考えたほうがいい。
JOINの多用の場合、注意していただきたいのは、SQL文のよしあしだ。
ある人(3年くらいの経験者なんだけど)SQLの1文が1万6千文字!とかいう人がいたけど。。。そりゃーきびしいものがあるんでないかい(^^;)
2番目のorder byに関して、じゃあ、DBでやらない場合、どこでやるのさ?っていう話。たしかに、受け取ってきてからソートしたほうが、早い場合がある。
つまり、データのResultSetから、1行1行とってきて、ハッシュマップに入れる。
ハッシュマップの
キー:ソートしたいキー(仮にキーの型はStringだとします)
値:とってきたデータ1行分
で、そのハッシュマップをmpとすると、
String[] keylist = (String[])mp.keySet().toArray(new String[0]);
で、キーをStringの配列として取得できる。
その後
Arrays.sort(keylist);
とすると、キーがソートして取得できるので、あとは、
Vector kekka = new Vector();
for(int i = 0 ; i <keylist.length;i++)
kekka.add(mp.get((String)keylist[i]));
}
とかやると、kekkaに、ソートした結果が入る。
いま、昇順だったけど、降順にしたい場合は、
for(int i = keylist.length ; i >= 0;i--)
にすればいい。
キーが3つか4つあるとき、
全部昇順、全部降順なら、3つなり4つなりのキーを
item1 + " " + item2 + " " + item3
のように、スペース(スペースが値としてありえないとき)やタブでつないで、
ハッシュマップにいれればよい
(数字の場合は、桁数あわせが必要になるかも。文字も桁数合わせたほうがいいかも)
でも、昇順と降順が入り混じる場合は、この方法は出来ない。
ただし、上記の方法を行った場合、むしろ、order byを行ったほうより、遅くなる場合がある。
このケースは、たとえば、この処理を行うプログラムが、サーバーサイドのようなプログラムのときで、サーバーで、いっぺんにみんなが、ハッシュマップをとってしまうとき、あるおばかなプログラムが、100万件分のハッシュマップを使う!みたいなことをやられると、すっげーメモリをとられてしまい、そのプログラムが終わったあと、急にガベージコレクションが走ると、周りが迷惑する。
なんで、ウィリアムのいたずらは、自分で、大きくメモリーを何回も使いそうなときは、自分でgc()を起動している。結構、思ったより、早くなる”こと”もあるよ!
でも、order byより、遅くなるようなら、素直にorder byしたほうがいいぽ。
可読性がわるくなるぽ!
ifnest??これが気にかかる。。。
RDBの話?
一般の話?
一般的に言って、ifのネストはよみにくくなるよね。
でも、じゃあ、状態遷移表や、決定表で書かれたとき、ifのネストを使わないで、表現するには?って、いう話はみんなOKなのかなあ。。。
いや、このネタを書こうといつも思っているんだけどね、eclipseを立ち上げられないのよ、いま、Excelのバグフィックス中なんで。。。
(って、そんなとき、ブログ書いているなよ!<自分)
なんで、このネタについては今度eclipseを立ち上げられるときに。
・null
NULLを入れるとプログラムが落ちるというテストの話かもしれないけど、話の流れから、多分正規化の話だと思う。佐藤正美氏は、正規化をしないと噛み付くとか言ってる。
で、NULL値を利用すると、正規化しないですんじゃうものがある。
たとえば、衣料品と有機野菜を扱う会社があったとする(なんか、「あった!」なあ)
そんな会社だと、商品名にこまる。
衣料品はサイズ、色、がある。有機野菜は、サイズはあるものもあるけど。。。
トマトは、普通赤です
ピーマンはふつう緑です(赤いのは、赤ピーマンといいます)
バナナは黄色です(青いのは、黄色くなります。茶色いのは売っちゃだめです)
っていうわけで、色は、使わないです。
そこで、NULL値をいれてしまい、衣料品も有機野菜も1つのテーブルにしてしまう。
しかーし!それって、まずくないかい?
衣料品と、有機野菜は別々のもんだろう。テーブルを分けなさいと。。
っていう話。
正規化すると、JOINが多くなる=>っていうので、3番の話とつながる
ただ、この正規化を崩してNULLをいれるのを、世の人がやるのは、実際、JOINのスピードが遅いことから来ている。
確かに佐藤氏の主張するように、indexをはって、それでjoinが解決するようにすれば、うまくいくケースもおおい。しかし、更新系が頻繁に行われるシステムにおいては、今度は、更新スピードが問題になるし、佐藤氏自身も、joinで遅い場合はnative シーケンスを使うようだし。。。。
ただねえ。。。そーいうテクニックはオラクルには使えても、postgreSQLやmySQLでも使えるのか?おお、しんふぉうえあーは、どーなのどーなの!とかいう問題がある。
さらにわるいことに、この問題、あなたの上司の時代は、汎用機だから、あんまりおこらないと思う。
汎用機の場合、メモリ確保はJCLによって、プログラム起動前にあらかじめ行われる。したがって、ワークエリア取得のメモリ要求がきても、その範囲をわたすだけなので、そんなにかからない。
その上、INDEXやデータ領域に関しては、どこにおくかをシリンダレベルで、JCLで設定できる。これにより、INDEXを1シークでアクセスできるようにしてしまえば、すんげえDBアクセスは早くなる。
さらにだ、これを操作するCOBOL言語は動的にメモリを取らないし、プログラムが使用するメモリ領域はJCLにより起動時に取得するので、ガベージコレクションによって、遅くなるなんてことはない。
ということで、現場的には、「危険を覚悟で」こういうのを使うことになる。
なんで、現実的には、はじめ、可読性をあげておいて、あとで、スピードアップするために、こういうところの書き換えになるよねえ。
で、これについての、現実暴露話を書こうと思ったけど(可読性をあげるために、実はあえて、遅くなるプログラムを書くように指示が出る。。。でもでもね、それって。。。っていうような話)、もうそろそろ、お仕事しないとやばやばな「空気」なんで、きょうは、ここまで。
もしかすると、佐藤氏非難のように聞こえるかもしれないけど、とんでもないっす。
多くの場面では、佐藤氏の方法は、非常に有効だし、有効でない場面でも、この方法を意識して置くべきだと思う(意識して使わないということ)。
とりあえず、佐藤氏の話は一度は聞いておいたほうがいいと思う。
ただし、(誰の話でも)うのみにしないこと。
なんか、佐藤氏や、その周辺の人たちから、文句こないだろうなあ。。
きたら、このエントリー、そっこーで、削除します。