PL/SQL等のバッチ処理でたまに見かける最悪なプログラム - suVeneのアレ

PL/SQL等のバッチ処理でたまに見かける最悪なプログラム

今日はプログラムの話 & 愚痴。

プログラムしてる時は、わりと静かに黙々と作業している(と思う)。

ただ突然「あほかっ!」と叫んでしまいたくなることがある。いや、さすがに叫びはしないが、小さく呟くくらいはしているかもしれない。
(よくゴニョゴニョいいながらカチャカチャやってるプログラマーみたいな)

Zoobic_subic_monkey_13881_o

叫びたくなるプログラムとは?

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チューニングハンドブック--中小企業のIT化支援--キーゴールプロダクト・サービス–書籍一覧–SEのためのOracleチューニングハンドブック–中小企業のIT化支援–キーゴール プロダクト・サービス--書籍一覧--SEのためのOracleチューニングハンドブック--中小企業のIT化支援--キーゴール

本じゃなくて、とりあえず今すぐ何とか役立つ情報が欲しいよ~って人は、

SQLを速くするぞ―お手軽パフォーマンス・チューニングSQLを速くするぞ―お手軽パフォーマンス・チューニング SQLを速くするぞ―お手軽パフォーマンス・チューニング

とか役立つかも。

参考書籍

SEのためのOracleチューニングハンドブック

後藤 孝憲,名和 満,五嶋 和彦,井原 秀樹 ソフトバンククリエイティブ 2003-11-17
売り上げランキング : 329571

by ヨメレバ

スポンサーリンク
スポンサーリンク

コメント

  1. 匿名 より:

    よくありますね。
    最近はmerge文でselect/insert/updateの同時実行がお気に入りです。

  2. hanano_cash より:

    oracleバージョン古くないのでしょうか?
    なんとも判別しがたいです。

  3. ささき ひろし より:

    FETCH 文はSQLの仕様にないものと考えて、FETCHを使いたくなったら、方向性が根本から誤っていると感じることです。 くるくる回している仕様では、根本的な解決はできないと思うことです。SQLは集合論の延長であり、手続き型処理をするために存在するものではありません。

  4. えの より:

    バッチ処理の基本です。
    これが最悪だとは思いませんがね。

  5. 匿名 より:

    pl/sqlはどうにもクソだと思う。手続き型の処理で困るところを解決するためのデータベースに手続きを持ってくる発想自体頭おかしい。

  6. 匿名 より:

    これがバッチ処理の基本だと思ってるならクソオブクソだな。

  7. こっぷ より:

    少なくても「TRAN2」のSELECTにWHERE句がないなら
    LOOPの外に出すべきだと思います
    「MASTER」のWHERE句が主キーだとしたら、
    あとはUPDATEの条件次第でしょうか

    ※COUNTで存在チェックは重いので、COUNTはやめて、WHEREに「ROWNO <= 1」を付け、FETCHの結果を「%FOUND」で判定すると良いと思います(1件の該当有無)

コメントをどうぞ

メールアドレスが公開されることはありません。