Tips1. Oracleのパフォーマンス問題~存在チェックが遅い~

Oracle, PL/SQL, パフォーマンスcount, COUNT(1), パフォーマンス, 存在チェック

存在チェックにCOUNTを使わない!

もう、世の中的にはPL/SQLも古い言語に含まれると思うのですが、未だ存在チェックに暗黙カーソルのCOUNTを使う人がいます。
若者ならまだしも、そこそこの単価をもらっているベテランプログラマでも、こんな書き方をする人がいます。

SELECT COUNT(*) INTO ln_count
FROM tab_a;
--
IF ln_count = 0 THEN
  dbms_output.put_line('ERROR!');
  RAISE NO_DATA_FOUND;
END IF;

もう少し凝ったモノだと、カーソル中に

SELECT DECODE(COUNT(*), 0, TRUE, FALSE)
FROM tab_a;

みたいな・・・(実際にはもっと複雑なSQLですが)

このテーブルtab_aが数件しか無ければ大きな影響は無いかもしれませんが、億単位のデータを保持していたらどうなるでしょう。
処理性能に影響が出るのは言うまでも無いですよね。

では、どう書くのが良いのか。

DECLARE
  CURSOR c1 IS
  SELECT 1 FROM tab_a;
  ln_check NUMBER;
BEGIN
  OPEN c1;
  FETCH c1 INTO ln_check;
  IF c1%NOTFOUND THEN
    dbms_output.put_line('ERROR!');
    RAISE NO_DATA_FOUND;
  END IF;
  CLOSE C1;
 :
END;

と書きます。

こうすることで、テーブルtab_aに何件入っていようと、1件分のデータにしかアクセスしないようになります。

よく、

:
SELECT COUNT(*) INTO ln_count
FROM tab_a
WHERE ROWNUM = 1;  --←ここを追加
--
IF ln_count = 0 THEN
  dbms_output.put_line('ERROR!');
  RAISE NO_DATA_FOUND;
END IF;
:

でも良いのでは?と言われますが、あまり推奨したくはありません。

「データが存在するか」というロジックなのですから、素直に「存在するか」というロジックを書くことが、より可読性を向上させると思います。

「データが存在するか」というロジックに対し「件数をカウントする」は、間にワンステップ思考が入っています。よりシンプルな思考を求めるのであれば、COUNTの使用は避けた方が良いと思います。

ま、ここはムキになって否定するほどのポイントではないので、現場で見かけてもとやかく言うことはありませんが。

いずれにしても、存在チェックを行う際はデータアクセスを最小限に留めることが重要です。