今日はプログラムの話 & 愚痴。
プログラムしてる時は、わりと静かに黙々と作業している(と思う)。
ただ突然「あほかっ!」と叫んでしまいたくなることがある。いや、さすがに叫びはしないが、小さく呟くくらいはしているかもしれない。
(よくゴニョゴニョいいながらカチャカチャやってるプログラマーみたいな)
Contents
叫びたくなるプログラムとは?
DB更新を含むバッチ処理などで Pro*C 使ってたり PL/SQL 使ってたりするプロジェクトはよくあると思う。叫びたくなるのは、そういうプロジェクトの中で他人のプログラムを修正している時だ。
とは言っても、ソースが汚いとか main() や BEGIN END の間に全部の処理書いてるとか、それくらいでは叫びはしない(ていうか、全部直してる訳にはいかないので)。
ではどういう時かというと、「パフォーマンスが出ない」「バッチが朝までに終わらない」などと、オロオロしてる中に放り込まれて、いざ対象のソースを読むと「ループ中にファイルにアクセスする感覚で SELECT 句発行してたりするプログラム」だった時だ。
「ちょっと考えればわかるだろう!」とか、「仕様はどうなってんだ!」とか、「ソースレビューの段階で気づかないか?」とか色々意見はあるだろう。
おれもそう思う。
しかし、プロジェクトがちょっと大きめだったり、クソみたいな計画か、クソみたいな何かのせいで、
- コーディングは下請けに丸投げ
- プロジェクトに火がついて素人みたいなプログラマ大量投入して解決(したつもり)
- 途中で来なくなった人が多数
みたいな状況があったりして、「ソースレビューなんて、そりゃ正論ですし、できればいいですねー」という現実がまれによくある。
んで、「バッチ処理が遅い」だとか「バッチ処理が重い」だとか言ってるんだが、当たり前だろう!
例えば、具体的にどんなプログラムかっつーと
DECLARE count number; CURSOR cur IS SELECT id FROM TRAN; BEGIN FOR c IN cur LOOP -- マスタの値を取得 SELECT * FROM MASTER WHERE id = c.id; -- なんかの処理 -- -- 存在チェック SELECT COUNT(*) INTO count FROM TRAN2; IF (count = 0) THEN -- insert 処理 ELSE -- update 処理 END IF; END LOOP; END;
みたいな。
これでカーソルが数万とかの単位になるとそれだけで重くなるし、他にもカーソルの値で他のテーブル検索して 1ループ 1秒前後かかるとしたら、単純計算で 1秒 * 1万回。普通に2~3時間くらいかかったり。Join しとけよ!
つーか、大体 COBOL上がりの設計者で、PL/SQL 使ってバッチ作ろうって人に多いんだが(偏見です)、更新を行単位で処理しようとするんだな。どうしても必要な時は FETCH すりゃーいいけども、大抵の場合集合的に更新かけれるし、ムリならワークテーブルなりで対象データ絞れよな。Insert/Update 1万回するのと、1万行の更新を1回するのとの考え方の違いをわかってないっつーか。
まぁ、俺がこんなに怒ってるのは、今まさにそんなプログラムをメンテしたりしてるからであり、このめんどくせーって思いと怒りをどこかの誰かと共有するために書いてる訳だが、こういうプログラム見たことない?
「見たこと無い!」って言うあなたは、幸せモノです!
もしも不幸なプログラムに出逢ってしまったら?
- 一緒に取れるデータはなるべく一緒に取る
- Index 見直す
- 対象データを分割して、パラレルに処理出来ないか検討する
もしくは、そんな小手先では通用しないならば
今あるプログラムを捨てて作りなおす許可を得る努力を最大限する
というのが、一番幸せなパターンも有る。
きみが不幸なプログラムを生み出さないために
基本的なチューニングのイロハを身につけよう
Oracle であれば「SEのためのOracleチューニングハンドブック」がチューニングのバイブルとして使える。
この本は、こんな人に超おすすめ。
- SEになったばかりで、システム開発の作業の進め方がよくわからない人
- システム開発の工程ごとのチューニングポイントを知りたい人
- 分厚いマニュアルや書籍を読んでいる暇がない忙しいSEやプログラマ
- プロジェクトを円滑に遂行したいと思っているプロジェクトマネージャ
- チューニングの重要性はわかっているが、どこをどうチューニングすればいいかわからない人
- 索引さえはれば、Oracleの高速な検索が可能だと思っているプログラマ
- パフォーマンスチューニングの目標を具体的な数字で知りたいと思っているSEやプログラマ
本じゃなくて、とりあえず今すぐ何とか役立つ情報が欲しいよ~って人は、
とか役立つかも。
参考書籍
SEのためのOracleチューニングハンドブック 後藤 孝憲,名和 満,五嶋 和彦,井原 秀樹 ソフトバンククリエイティブ 2003-11-17
|
コメント
よくありますね。
最近はmerge文でselect/insert/updateの同時実行がお気に入りです。
oracleバージョン古くないのでしょうか?
なんとも判別しがたいです。
FETCH 文はSQLの仕様にないものと考えて、FETCHを使いたくなったら、方向性が根本から誤っていると感じることです。 くるくる回している仕様では、根本的な解決はできないと思うことです。SQLは集合論の延長であり、手続き型処理をするために存在するものではありません。
バッチ処理の基本です。
これが最悪だとは思いませんがね。
pl/sqlはどうにもクソだと思う。手続き型の処理で困るところを解決するためのデータベースに手続きを持ってくる発想自体頭おかしい。
これがバッチ処理の基本だと思ってるならクソオブクソだな。
少なくても「TRAN2」のSELECTにWHERE句がないなら
LOOPの外に出すべきだと思います
「MASTER」のWHERE句が主キーだとしたら、
あとはUPDATEの条件次第でしょうか
※COUNTで存在チェックは重いので、COUNTはやめて、WHEREに「ROWNO <= 1」を付け、FETCHの結果を「%FOUND」で判定すると良いと思います(1件の該当有無)