我在EF6中遇到緩慢的LINQ查詢編譯問題。我知道EF緩存編譯後的LINQ查詢查詢計劃,但是有一些陷阱(例如Enumerable.Contains阻止緩存)。我想查看緩存以進行調試,以驗證我是否正在爲我的查詢獲取適當的緩存。我怎樣才能做到這一點?如何查看實體框架LINQ查詢計劃緩存?
注意:因爲這純粹是爲了調試,所以我很樂意回答使用反射或其他方法,不會在生產中使用。
我在EF6中遇到緩慢的LINQ查詢編譯問題。我知道EF緩存編譯後的LINQ查詢查詢計劃,但是有一些陷阱(例如Enumerable.Contains阻止緩存)。我想查看緩存以進行調試,以驗證我是否正在爲我的查詢獲取適當的緩存。我怎樣才能做到這一點?如何查看實體框架LINQ查詢計劃緩存?
注意:因爲這純粹是爲了調試,所以我很樂意回答使用反射或其他方法,不會在生產中使用。
可以使用這樣的事情(在EF 6.1.3)反映到緩存:
var method = context.Database.GetType().GetMethod("CreateStoreItemCollection", BindingFlags.Instance | BindingFlags.NonPublic);
var storeItemsCollection = method.Invoke(context.Database, null);
var queryCacheManagerField = storeItemsCollection.GetType().GetField("_queryCacheManager", BindingFlags.Instance | BindingFlags.NonPublic);
var queryCacheManager = queryCacheManagerField.GetValue(storeItemsCollection);
var cacheField = queryCacheManager.GetType().GetField("_cacheData", BindingFlags.Instance | BindingFlags.NonPublic);
var cacheData = cacheField.GetValue(queryCacheManager) as ICollection;
foreach (var item in cacheData)
{
Console.WriteLine(item.ToString());
}
不幸的是,在高速緩存中的所有項目都internal
類型(在System.Data.Entity.Core.Common.QueryCache
命名空間),所以從他們那裏獲得有用的信息將需要更多的思考和探索。幸運的是,CompiledQueryCacheKey
覆蓋了ToString
,所以它放棄了一些關於它自己的(神祕的)信息。運行一個查詢(Table.Count()
)後,上面的代碼吐出這兩個條目:
[System.Data.Entity.Core.Common.QueryCache.ShaperFactoryQueryCacheKey`1[System.Int32], System.Data.Entity.Core.Common.QueryCache.QueryCacheEntry]
[FUNC<Edm.Count(In Transient.collection[Edm.Int32(Nullable=True,DefaultValue=)](Nullable=True,DefaultValue=))>:ARGS(([Project](BV'LQ1'=([Scan](DashboardAutoContext.Organizations:Transient.collection[DashboardAuto.Organization(Nullable=True,DefaultValue=)]))(1:Edm.Int32(Nullable=True,DefaultValue=)))))|||AppendOnly|True, System.Data.Entity.Core.Common.QueryCache.QueryCacheEntry]
好運搞清楚這是什麼意思,或者當你有一大堆項的東西相關。
我已經取得了一些成功的另一種策略是使用我可以在測試期間分配給DbContext.Database.Log
的方法創建一個類。該類在看到「Opened connection ...」消息時啓動計時器,然後在看到「 - 正在......執行」時停止該計時器。這段時間大致對應於EF將LINQ查詢編譯爲SQL所花費的時間。如果您的查詢被緩存,那麼在第一次執行查詢之後,這個時間將縮小到幾乎沒有的時間;如果它沒有被緩存,時間將保持一貫高。
(應該不用說,你只需要做到這一點在測試範圍內。)
您可以注入IDbCommandTreeInterceptor
實施記錄任何查詢樹創作。我成功地將它與調用堆棧鍵控字典結合使用,以發現多個「錯誤」查詢的彙編。
你的意思是SQL服務器緩存查詢計劃,而不是EF? – Magnus
@Magnus EF緩存LINQ to SQL的翻譯。 SqlServer將SQL的翻譯緩存到執行查詢的「查詢計劃」。我對EF的工作很感興趣。 – ChaseMedallion
好的,所以你對查詢本身感興趣,而不是查詢計劃。 – Magnus