EzJDBCで危険な香りのするSQLを検知する機能!vol.2/調子に乗って...


こんにちは、EzJDBCはSQLを意識したO/Rマッパーなので、既存のSQLの知識もいかせて良いですよーとほざいては空ぶってばかりいる高橋です。
そんな私が、今回ご照会するのはEzJDBCで危険な香りがするSQLを検知する機能 VOL.2 です。
ところで、危険な香りがするSQLとは、どんなSQLなのでしょうか?
ずばり、ORDER BY句が指定されていないSQLなのです...
ORDER BY句が指定されていないSQLは無条件に危険とは言えないかもしれませんが、かなりの確立で危険度が高いSQLであることは間違いありません。
何故なら、ORDER BY句のないSELECTの、取得する結果の順番は不定となるからです。
そこで、EzJDBCまたはEzTxを利用してSQLを発行した場合は、SELECTのSQLにORDER BY句が指定されていない場合にWarningメッセージを出力する機能を提供します。
それでは、ORDER BY句が指定されていないSELECTのSQLが発行された場合に、SQLログにワーニングメッセージを出力する場合の例を見てみましょう。


Javaコード
CUSTOMER, IRDERS, ORDER_ITEMの3テーブルを結合し、結果を取得するEzJDBCのコード

 List list = selects().from(CS).join(OD, OI).find(Customer.class);


上記コードの実行結果のSQLログ
青字のログがSELETC文のSQLのORDER BY句が含まれていなかった時に出力されるログです。
赤字について説明します。
1.ログレベル「WARN」で出力されます。
2.ORDER BY句のついていないSQLを出力します。
3.2のSQLが発行された時刻をと応答時間を出力します。この情報により、どの処理で呼び出されたSQLかが判別可能になります。
赤字以降のログは、考えられる改善策が出力されます。

[16585653] DEBUG 2010-11-15 18:09:52.546 [main] トランザクションを開始しました
[16585653] DEBUG 2010-11-15 18:09:54.656 [main] コネクションを取得しました(JDBC接続)
[16585653] DEBUG 2010-11-15 18:09:54.875 [main] SELECT CS.CODE,CS.NAME,CS.VERSION,OD.ORDER_NO,OD.CUSTOMER_CODE,OD.CREATED,OI.ORDER_NO,OI.SEQ FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO)
[16585653] WARN 2010-11-15 18:09:54.953 [main] SELECT文にORDER BY句未設定の警告 ...

                                                                                                                                                                  • -

下記のSQLにORDER BY句が未設定です。
ORDER BY句のないSELECTの、取得する結果の順番は不定となります。対象となるSQL文 : SELECT CS.CODE,CS.NAME,CS.VERSION,OD.ORDER_NO,OD.CUSTOMER_CODE,OD.CREATED,OI.ORDER_NO,OI.SEQ FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO)
SQLが発行された時間は、「2010-11-15 18:09:54.875」です。

                                                                                                                                                                  • -

【考えられる改善策】
1.ORDER BY句で結果の順番が一定になるように並び順を指定してください。
ORDER BY句で指定するソートの順番はユニークになる様にしてください。
2.抽出条件に一位の条件を指定している場合や、取得結果の並び順の指定を必要としない場合。
EzJDBCのorderByNothingメソッドを呼び出し、ORDER BY句が不要であることを明示して下さい。

[16585653] DEBUG 2010-11-15 18:09:55.265 [main] SQLの実行が完了しました
[16585653] DEBUG 2010-11-15 18:09:55.265 [main] コミットしました
[16585653] DEBUG 2010-11-15 18:09:55.265 [main] コネクションを返却しました
[16585653] DEBUG 2010-11-15 18:09:55.265 [main] トランザクションを終了しました

単なるORDER BY句の付け忘れであれば、EzJDBC#orderByメソッドで並び順を指定すればよいことになります。
しかし、常に取得結果が1件の場合や処理的に並び順を考慮する必要が無い場合もあるかと思います。
その場合は、毎回警告が出力されるのは良くありませんので、明示的にEzJDBC#orderByNothingメソッドを呼び出します。


Javaコード
並び順を合えて指定しない場合のコード例

 List list = selects().from(CS).join(OD, OI).orderByNothing().find(Customer.class);


上記コードの実行結果のSQLログ

[16585653] DEBUG 2010-11-15 18:23:08.718 [main] トランザクションを開始しました
[16585653] DEBUG 2010-11-15 18:23:10.687 [main] コネクションを取得しました(JDBC接続)
[16585653] DEBUG 2010-11-15 18:23:10.890 [main] SELECT CS.CODE,CS.NAME,CS.VERSION,OD.ORDER_NO,OD.CUSTOMER_CODE,OD.CREATED,OI.ORDER_NO,OI.SEQ FROM CUSTOMER as CS left join ORDERS as OD on (CS.CODE=OD.CUSTOMER_CODE) left join ORDER_ITEM as OI on (OD.ORDER_NO=OI.ORDER_NO)
[16585653] DEBUG 2010-11-15 18:23:11.265 [main] SQLの実行が完了しました
[16585653] DEBUG 2010-11-15 18:23:11.281 [main] コミットしました
[16585653] DEBUG 2010-11-15 18:23:11.281 [main] コネクションを返却しました
[16585653] DEBUG 2010-11-15 18:23:11.281 [main] トランザクションを終了しました

警告が出力されなくなりました。
警告を出力しないためにorderByNothingメソッドをわざわざ呼び出すことに面倒だと感じた方もいるかと思います。
しかし、orderByNothingメソッドを明示的に記述するには意味があります。システムの保守フェーズの際にORDER BY句が指定されていないのが潜在バグなのか、意味があることなのかをコードから
保守担当者に伝えるためです。
また、本当にORDER BY句の指定を忘れてしまった時には、開発段階で潜在バグ化する可能性のあるコードを気づかせることが出来ます。



このように危険度の高いSQLを開発段階から潰すことが可能に


するのが、EzJDBCなのです....( ̄0 ̄)b