ついカッとなってS2Dao.NETの機能を使わずに検索処理を書いてみた
Seasar+S2Daoを使ったプロジェクトで、
開発終盤、もしくは結合テストなどを行う頃になると
高確率で言われる台詞があります。
「○○の処理でパフォーマンスが出ない。
S2Daoは色々リフレクションとか使ってるから
そのせいで遅いんじゃないの?」
というようなものです。
実際にはS2Daoの中であれこれやっている処理よりも
SQL文そのものに問題があったり
DBアクセスとは関係ない部分がボトルネックだったりすることも
多いのですが、
.NETならADOを直接たたいた場合の方が速いのは事実です。
大まかに以下のような処理を行っているためです。
1.Entityのプロパティなどのメタデータから
DBアクセスの実行に必要な情報を読み取る。
2.ADO.NETを使ってSQL文を実行する。
3.返ってきた結果をEntity(もしくはそのリスト)に格納する。
1.については大部分がキャッシュされますが
それでも初回実行時にはそれなりにコストがかかります。
なので、初回実行時のコストや
Entityに検索結果を自動的に詰め込む分のコストなど、
少しでもオーバーヘッドを削りたい場合のために、
以下のようなコードを考えてみました。
※DBFluteの使用が前提です。
※今のところSeasar.NETでの実装予定はありません。
※厳密にエラー処理等を検証したわけではないので
参考程度、と思って下さい。
検索を実行する場合はSimpleSelectHandlerのExecuteメソッドを呼び出します。
///
/// 最低限の機能のみをもつ検索ハンドラ
///
[Implementation]
public class SimpleSelectHandler
{
(途中省略)
///
/// 検索実行
///
///
///
///検索結果
public virtual object Execute(string sql, IDataReaderHandler handler){
IDbConnection connection =
DataSourceUtil.GetConnection(_dataSource);
object ret = null;
try {
ret = ExecuteCommand(sql, handler, connection);
}
finally {
_dataSource.CloseConnection(connection);
}
return ret;
}
(以下略)
}public class ExampleDataReaderHandler : IDataReaderHandler {
public object Handle(IDataReader dataReader) {
Member member = new Member();
member.MemberId = dataReader["MEMBER_ID"] as int?;
member.MemberName = dataReader["MEMBER_NAME"] as string;
return member;
}
}
Executeメソッドの中で呼んでいるExecuteCommandの中で
やっている処理は大雑把に言えば
IDataReaderHandler型の引数handlerからHandleメソッドを呼んで
結果を返すことのみです。
Executeメソッドの第2引数IDataReaderHandlerは
上記ExampleDataReaderHandlerのような感じで
自前で実装します。
もう一つの引数には実行したい生のSQL文字列を渡します。
DBFluteのConditionBeanにはToDisplaySqlというメソッドがあり、
戻り値としてそのまま実行可能なSQL文字列が返ってきます。
それを渡せばSQLの組み立て部分については
ある程度タイプセーフは保てる(はず)。
上記実装を含むパフォーマンス比較結果はこちら