LINQ to Entitiesではまったところとか
今の会社とは違うとある案件でEntityFrameworkを使っているのですが、なぜかやたら遅くて、原因がわからずじまいでした。
今日はその原因と、そのほかはまりどころがわかったのでメモです。
発行されているクエリを確認する
これができないことには原因の調べようがありません。
とりあえずデバッグログに放流するには
using(var context = new DbContext()) { context.Database.Log = Debug; }
という感じでDebugクラスを渡しておくとできます。
クエリが実行されると
Opened connection at 2015/03/03 20:20:38 +09:00 SELECT .... -- p__linq__0: '*******' (Type = String, Size = 4000) -- Executing at 2015/03/03 20:20:38 +09:00 -- Completed in 52 ms with result: SqlDataReader Closed connection at 2015/03/03 20:20:38 +09:00
といった風に
- 接続した時刻
- 発行されたクエリ
- 変数(あれば)
- クエリを実行した時刻
- クエリのコンパイルに要した時間
- 接続を閉じた時刻
が出力されるようになります。
今回ミスってた原因
ちなみに今回の原因はプロパティのgetterにそれ書いていたことのようです。
外部キーとかなかったので、せめてそんな感じでアクセスできたらなーというほんの出来心でした。
これにより、プロパティの思った通りのクエリが構築されておらず、getterの部分に書いてあった最低限の制約条件でSQLのクエリが発行されてしまい、その結果大量のレコードがやりとりされ、それらがメモリによっこいしょと載せられて、ごりごりとリソースを消費しながら計算・集計されていた、というわけです。
その辺に気を付けながらクエリ式を修正しつつちゃんとSQLにコンパイルされるようにすると、3分かかってた処理が3秒になりました。メモリも数GB使っていたものが数十MBまで減りました。
あれが使いたいこれが使いたい
IN
`.List
LIKE '%hoge'
`String.StartWith(string)` や `String.EndWith(string)`
が使えます。 `String.Contains(string)` の場合、最初と最後に「/」を書くとそれが「%」になるようです。
MiN、MAX、COUNT
LINQのMin, Max, Countでどうぞ。
Left関数
今日初めて知ったのですが、渡した文字列の左から、指定した文字数だけの文字列を返すという関数です。
これをEntitieFrameworkで使うには、 `System.Data.Entity.DbFunctions.Left(string, left?)` を使います。