3

私は自分のアプリケーションの速度の最適化に取り組んでいますが、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 を生成するにはどうすればよいですか?

事前にt​​hx!

4

5 に答える 5

3

あなたは何であるかは言いません_DatabaseViewが、あなたの結果に基づく私の大雑把な推測では、ObjectQuery<T>. これはあなたの問題を説明します。ObjectQuerySQL に変換されます。IEnumerable<T>.Skip()しません。これを実現するにAsQueryable()は、列挙型を呼び出すだけでは不十分です。

たとえば、次のようになります。

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

... TOPSQLに入れません。

でもこれは:

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

... 意思。

繰り返しますが、あなたは が何_DatabaseView であるかを言っていません。この操作を で直接試してみるObjectContextと、うまくいくことがわかります。バグは、割り当て_DatabaseViewに使用するコードにありますが、表示されていません。

于 2010-10-25T15:43:30.913 に答える
2

LINQ パーサーは、LINQ to Entities クエリのメソッドSkipとメソッドを確実に考慮し、正しい式ツリーを生成します。次に、オブジェクト サービスが式ツリーをコマンド ツリーに変換します。コマンド ツリーは、特定の SQL クエリ生成のためにデータベース プロバイダーに渡されます。 この場合、生成された SQL に影響を与えるこの 2 つのメソッドは、それぞれ aとforとfor を使用します。 さて、プロファイラーで正しいトレースを見ていると確信していますか? プロファイラーに移動する前に以下のコードを記述してObjectQuery.ToTraceStringメソッドを確認し、コードをデバッグしてsqlの値を調べることをお勧めします。Take
WHERE [Extent1].[row_number] > 50SELECT TOP (25)SkipTake

変数:

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();
于 2010-10-25T14:44:57.313 に答える
2

使用されている SQL を実際に変更できる唯一の方法は、生成された SQL を使用する代わりに、独自の SQL を記述してそれを使用することです。

つまり、LINQ の Skip 部分と Take 部分が SQL に変換されていないということです。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であるべきだとあなたが言った部分を見逃しました。

于 2010-10-25T14:07:21.153 に答える
0

Select の前に Skip と Take を移動してみてください。

于 2010-10-25T15:05:48.493 に答える
0

適切なインデックスを使用して SQL を十分に実行できない場合は、いつでもストアド プロシージャを記述して、それを LINQ から呼び出すことができます。

于 2010-10-25T14:14:49.057 に答える