質問

私はアプリケーションの速度の最適化に取り組んでいますが、LINQ (または EF) が動作が遅い奇妙な SQL を作成していることがわかりました。

ここにいくつかのコードがあります:

SomeList.AddRange(_databaseView
                .Select(l=> new SomeViewModel
                                {
                                    Date = l.Date,
                                    Details = l.Details,
                                    Level = l.LevelName,
                                    Id = l.ViewID,
                                    Message = l.Message,
                                    ProjectName = l.projectName,
                                    StatusId = l.StatusID,
                                    StatusName = l.StatusName
                                })
                .Skip(50)
                .Take(25));

そして理論的には、25レコードを取るSQLステートメントを作成するはずですが、プロファイラーはそれに対して次のSQLを表示します。

    SELECT [Extent1].[Date]  AS [Date],
       [Extent1].[ID]            AS [ID],
       [Extent1].[LevelID]       AS [LevelID],
       [Extent1].[StatusID]      AS [StatusID],
       [Extent1].[projectName]   AS [projectName],
       [Extent1].[LevelName]     AS [LevelName],
       [Extent1].[StatusName]    AS [StatusName],
       [Extent1].[Message]       AS [Message],
       [Extent1].[Details]       AS [Details],
       [Extent1].[LogViewID]     AS [LogViewID]
FROM   (SELECT [v_MyView].[Date]       AS [Date],
               [v_MyView].[ProjectID]     AS [ProjectID],
               [v_MyView].[LevelID]       AS [LevelID],
               [v_MyView].[StatusID]      AS [StatusID],
               [v_MyView].[projectName]   AS [projectName],
               [v_MyView].[LevelName]     AS [LevelName],
               [v_MyView].[StatusName]    AS [StatusName],
               [v_MyView].[Message]       AS [Message],
               [v_MyView].[Details]       AS [Details],
               [v_MyView].[ViewID]        AS [ID]
        FROM   [dbo].[v_MyView] AS [v_MyView]) AS [Extent1]

_databaseView は、すべての並べ替えとフィルター処理のロジックが実行される IQueryable オブジェクトです。

ここに私が考えたことがあります:フィルタリングを行わない場合、SQL は SELECT TOP (25) を使用して正常に実行されます。しかし、フィルタリングを行うたびに、何かが台無しになります。これは私のフィルターの1つのコードです:

if (Filters.ProjectName != null && Filters.ProjectName[0] != 0)    // check if "all" is not checked
    _databaseView = Filters.ProjectName
        .Join(_databaseView,  f => f, l => l.ProjectID,  (f,l) => new SomeViewModel
                                                                           {
                                                                               Date = l.Date,
                                                                               Details = l.Details,
                                                                               LevelName = l.LevelName,
                                                                               ViewID = l.ViewID,
                                                                               Message = l.Message,
                                                                               projectName = l.projectName,
                                                                               StatusID = l.StatusID,
                                                                               StatusName = l.StatusName
                                                                           })
    .AsQueryable();

そしてそれは何の制約もありません。この LINQ-EF を使って適切な SQL を生成するにはどうすればよいでしょうか?

事前にお願いします!

役に立ちましたか?

解決

あなたは_DatabaseViewが何であるかを言うことはありませんが、あなたの結果に基づいて、私の野生の推測では、それはObjectQuery<T>ではないということです。これはあなたの問題を説明するだろう。 SQLに変換しますObjectQueryIEnumerable<T>.Skip()はしません。列挙上AsQueryable()を呼び出すと、これを実現するのに十分なのないのです。

たとえば、この:

var foo = MyObjectContext.SomeEntitySet.AsEnumerable().AsQueryable().Take(10);

... SQLでTOPを入れません。

しかし、これます:

var bar = MyObjectContext.SomeEntitySet.Take(10);

...意志ます。

もう一度:あなたは何_DatabaseView の言っていません。あなたのObjectContext上で直接この操作を試してみて、あなたはそれが動作することを確認できます。バグはあなたが私たちを示していないアサイン_DatabaseViewに使用したコードである。

他のヒント

あなたが実際に使用されているSQLを変更することができます唯一の方法ではなく、生成されたSQLを使用することを自分自身と使用を書くことになります。

あなたはスキップを意味し、SQLに変換されていないLINQの部分を取ります。私はそれが原因であなたがLINQをやっていることな方法であると思います。

タグのようなものを試してみてください
(From l In DataBaseView Select new SomeViewModel
                                {
                                    Date = l.Date,
                                    Details = l.Details,
                                    Level = l.LevelName,
                                    Id = l.ViewID,
                                    Message = l.Message,
                                    ProjectName = l.projectName,
                                    StatusId = l.StatusID,
                                    StatusName = l.StatusName
                                }).Skip(50).Take(25)

その代わり、それが生成されたコードの違いを作るかどうかを確認します。

編集どういうわけか、私はあなたはそれが25回の記録を取るSQLべきであると述べた部分を逃しています。

LINQパーサは間違いエンティティクエリにあなたのLINQでSkipTake方法を検討し、正しい式ツリーを生成し、のオブジェクトサービスのは、データベースに渡されるコマンドツリーに式ツリーを変換し、特定のSQLクエリを生成するためのプロバイダ。
この場合、この2つの方法は、それぞれWHERE [Extent1].[row_number] > 50SELECT TOP (25)ためSkipTakeで生成されたSQLに影響を与えます。

さて、あなたは、のプロファイラの右のトレースを見ていることを確信していますか?私は <強いを見てみましょう示唆します> ObjectQuery.ToTraceString ののメソッドのプロファイラそして、あなたのコードをデバッグし、のSQL の変数ます:

var query = _DatabaseView.Select(l=> new SomeViewModel {
                                                     Date = l.Date,
                                                     Details = l.Details,
                                                     Level = l.LevelName,
                                                     Id = l.ViewID,
                                                     Message = l.Message,
                                                     ProjectName = l.projectName,
                                                     StatusId = l.StatusID,
                                                     StatusName = l.StatusName})
                         .Skip(50)
                         .Take(25));
string sql = (query as ObjectQuery).ToTraceString();
あなたは適切なインデックスを十分に実行するSQLを取得できない場合、

あなたは常に、ストアドプロシージャを書いてみてください可能性があり、ちょうどLINQからのことを呼び出します。

スキップを動かしてみて、選択の前に取ります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top