SQL記述の解析結果のキャッシュ

Jan 29, 2012 at 12:53 AM

こんにちは。お世話になっています。

 

Somaを用いたプログラムにて、大量データの投入処理にてOutOfMemoryが発生しました。

StackTraceの抜粋は以下のとおり

Exception rethrown at [0]:
   場所 Soma.Core.SqlModule.Parse(String sql)
   場所 <StartupCode$Soma-Core>.$Db.get_CacheSqlParser@98-1.Invoke()
   場所 System.Lazy`1.CreateValue()
   場所 System.Lazy`1.LazyInitValue()
   場所 System.Lazy`1.get_Value()
   場所 <StartupCode$Soma-Core>.$Db.get_CacheSqlParser@98.Invoke(String arg)
   場所 Soma.Core.SqlModule.prepareCore(IDbConfig config, String sql, IDictionary`2 exprCtxt, Func`2 parser)
   場所 Soma.Core.SqlModule.prepare(IDbConfig config, String sql, IDictionary`2 exprCtxt, Func`2 parser)
   場所 Soma.Core.DbImpl.Execute(String sql, IDictionary`2 exprCtxt)
   場所 Soma.Core.LocalDb.Execute(DbConnection connection, String sql)

 

これは、対象のコードを見てみたら、SQL記述にて

ID = /* id */0

と記述しているのではなく、

ID = {0}

として、string.Formatで値を入れてSQL発行していたのが問題で、これを直して解決しました。

 

ただ、Somaに対して2点ほど要望があります。

 

1.検索条件を指定しない場合はキャッシュしなくて良いのではないか?

検索条件(condition)を指定しない場合は、キャッシュする意味はないのではないでしょうか?

 

2.SQL記述の解析結果のキャッシュの上限値の設定

Javaで言えばCommons CollectionのLRUMapのような機構を使って、キャッシュの上限値が設定できると良いと思います。

 

実際にSomaコードを見れれば良いのですが見れておらず、ひょっとして上記考慮済みのコードでしたらごめんなさい。

 

以上、よろしくおねがいします。

Jan 29, 2012 at 3:17 AM

どうもー。

 

> 1.検索条件を指定しない場合はキャッシュしなくて良いのではないか?

Somaは、SQLを木構造のデータで管理していますが、木構造への変換処理を少なくするためにキャッシュをしています。

一度しか使わないSQLに対してはキャッシュが不要だと言えますが、検索条件が無くても同一のSQLが何度も実行される場合は、キャッシュがあったほうが効率的だと思います。

 

> 2.SQL記述の解析結果のキャッシュの上限値の設定

ConfigのクラスでSqlParserというプロパティをオーバーライドして任意のアルゴリズムをもったキャッシュを追加できます。
単純化していますが次のように書けます。 

 

public class MyConfig : MsSqlConfig
{
  private readonly Func<string, SqlAst.Statement> _sqlParser = sql =>
  {
    // get the result from the cache
    ...

    // if not cached, parse
    var result = SqlModule.Parse(sql);

    // save the parsed result to the cache
    ...

    return result;
  };

  public override Func<string, SqlAst.Statement> SqlParser { get { return _sqlParser; } }

  ...
}

 

ちなみにですが、単にキャッシュを無効にしたいだけならば、次のように記述できます。 

public class MyConfig : MsSqlConfig
{
  public override Func<string, SqlAst.Statement> SqlParser { get { return NoCacheSqlParser; } }
  ...
}

今はSqlParserのFuncのパラメータはSQLだけなのですが、将来のバージョンでは検索条件も渡すようにしたほうがいいかもしれませんね。
そうすると、検索条件にnoCacheと指定されている場合はキャッシュしないとか、そういった仕組みが書きやすくなります。 

このあたり、何か意見あれば聞かせてください。

 

> 実際にSomaコードを見れれば良いのですが見れておらず、ひょっとして上記考慮済みのコードでしたらごめんなさい。

いえいえ、気軽に聞いてください。
現状、ドキュメントがきれいに整備されてないですからねー。

Jan 30, 2012 at 2:39 PM

こんばんは

 

> ConfigのクラスでSqlParserというプロパティをオーバーライドして任意のアルゴリズムをもったキャッシュを追加できます。

こうやって、簡単に拡張できるのはすばらしいですね。ちょっと時間ができたら、ほかにも面白いことができないかソース読んでみます。

1.6で実装された、IConnectionObserverとICommandObserverについても見てみます。

 

> 今はSqlParserのFuncのパラメータはSQLだけなのですが、将来のバージョンでは検索条件も渡すようにしたほうがいいかもしれませんね。
> そうすると、検索条件にnoCacheと指定されている場合はキャッシュしないとか、そういった仕組みが書きやすくなります。

そうですね。いろいろと夢が広がりそうですね。

 

> 現状、ドキュメントがきれいに整備されてないですからねー。

約束は決してできないですが、時間ができたら何かお手伝いさせてください。

 

ありがとうございました。

Jan 31, 2012 at 1:14 AM

 

> 1.6で実装された、IConnectionObserverとICommandObserverについても見てみます。

これらもドキュメント化できていませんね。。。

 

> 約束は決してできないですが、時間ができたら何かお手伝いさせてください。

ありがとうございます。
ご協力いただけると大変うれしいです。

いつでも構いませんのでお時間があるときに、メールください。
ドキュメントやコードをコミットできるように権限設定させていただきます。