engineer diary

エンジニアの日々の感想です

SQL速度化対応①

SQLの速度化対応です。
プログラムの実行時間が最近になって目に見えて遅くなり、
原因を調べたところ、SQLに問題があることが分かりました。
速度を考慮していない残念なSQLだったので、手直しをしました。
以下が手直し前のプログラムです。
※DBはOracleです。

SqlStr  = "SELECT A.XXX";
SqlStr += "     , A.YYY";
SqlStr += "     , A.ZZZ";
SqlStr += "  FROM (SELECT * FROM ABC";
SqlStr += "        UNION ALL";
SqlStr += "        SELECT * FROM DEF";
SqlStr += "       ) A";
SqlStr += " WHERE A.VVV = 'hoge'";
SqlStr += "   AND A.WWW = 'hogehoge'";

CountSqlStr = "SELECT COUNT(*) FROM(" + SqlStr + ")";
Count = SqlExec(CountSqlStr);

IF(Count > 0)
   SqlExec(SqlStr);
END IF;

※関数や記述ルールは適当です。

それぞれ
ABCが50万件
DEFが20万件
両方VIEWテーブルなので、UNION ALLで無条件に取得するとレスポンスに時間がかかってしまいます。

以下が手直し後のSQLです。

SqlStr  = "SELECT A.XXX";
SqlStr += "     , A.YYY";
SqlStr += "     , A.ZZZ";
// ①必要項目のみをSELECTする
// ②WHERE区はUNION時のSELECT区に付ける
SqlStr += "  FROM (SELECT XXX";
SqlStr += "             , YYY";
SqlStr += "             , ZZZ 
SqlStr += "          FROM ABC";
SqlStr += "         WHERE VVV = 'hoge'";
SqlStr += "           AND WWW = 'hogehoge'";
SqlStr += "        UNION ALL";
SqlStr += "        SELECT XXX";
SqlStr += "             , YYY";
SqlStr += "             , ZZZ 
SqlStr += "          FROM DEF";
SqlStr += "         WHERE VVV = 'hoge'";
SqlStr += "           AND WWW = 'hogehoge'";
SqlStr += "       ) A";

// ③1件でもあるかどうか分かればいいので、ROWNUMを使い、実行時間を短縮
CountSqlStr = "SELECT COUNT(*) FROM(" + SqlStr + ") ROWNUM <= 1";
Count = SqlExec(CountSqlStr);

IF(Count > 0)
   SqlExec(SqlStr);
END IF;

対策内容は、
①必要項目のみをSELECTする
②WHERE区はUNION時のSELECT区に付ける
③1件でもあるかどうか分かればいいので、ROWNUMを使い、実行時間を短縮
結果、実行時間がかなり短縮されました。

今後も、速度対応の記事を載せていこうと思います。

パフォーマンス改善と事前対策に役立つ Oracle SQLチューニングSQLチューニング (DB SELECTION)

パフォーマンス改善と事前対策に役立つ Oracle SQLチューニングSQLチューニング (DB SELECTION)