2016-03-25 1 views
0

私は、ODataの5.8.0と6.1.3 EntityFramework、クエリを使用しています:〜20をとる悪いのODataエンティティフレームワークとトップとパフォーマンスとのOrderBy

SELECT TOP (10) 
    [Project1].[FieldA] AS [FieldA], 
    [Project1].[FieldB] AS [FieldB], 
    FROM (SELECT [Project1].[FieldA] AS [FieldA], [Project1].[FieldB] AS [FieldB], row_number() OVER (ORDER BY [Project1].[FieldB] DESC, [Project1].[FieldA] ASC) AS [row_number] 
     FROM (SELECT 
      [Extent1].[FieldA] AS [FieldA], 
      [Extent1].[FieldB] AS [FieldB], 
      FROM [dbo].[table] AS [Extent1] 
      WHERE ([Extent1].[FieldA] = 'ABCDEFG') OR (([Extent1].[FieldA] IS NULL) AND ('ABCDEFG' IS NULL)) 
     ) AS [Project1] 
    ) AS [Project1] 
    WHERE [Project1].[row_number] > 0 
    ORDER BY [Project1].[FieldB] DESC, [Project1].[FieldA] ASC 

:中

&$filter=fieldA eq 'ABCDEFG'&$skip=0&$top=10&$orderby=fieldB desc 

結果

:私は同じLINQを使用する場合は、フィールドA.

の大量のためのDBに対して実行する秒実行するために120msのを取る

SELECT 
    [Limit1].[FieldA] AS [FieldA], 
    [Limit1].[FieldB] AS [FieldB] 
    FROM (SELECT [Limit1].[FieldA] AS [FieldA], [Limit1].[FieldB] AS [FieldB], row_number() OVER (ORDER BY [Limit1].[FieldB] DESC) AS [row_number] 
     FROM (SELECT TOP (10) [Project1].[FieldA] AS [FieldA], [Project1].[FieldB] AS [FieldB] 
      FROM (SELECT 
       [Extent1].[FieldA] AS [FieldA], 
       [Extent1].[FieldB] AS [FieldB] 
       FROM [dbo].[table] AS [Extent1] 
       WHERE ([Extent1].[FieldA] = 'ABCDEFG') OR (([Extent1].[FieldA] IS NULL) AND ('ABCDEFG' IS NULL)) 
      ) AS [Project1] 
      ORDER BY [Project1].[FieldB] DESC 
     ) AS [Limit1] 
    ) AS [Limit1] 
    WHERE [Limit1].[row_number] > 0 
    ORDER BY [Limit1].[FieldB] DES 

それはになります。

は、どのように私は(外文でTOPを使用しない、すなわち)のODataは同じ表現を使用するように強制するのですか?

+0

'$ skip'フィルタと' $ top'フィルタの順序を変更すると違いはありますか? '$ skip'述語を削除できますか? あなたはそれがEF ...提案のための – Nikita

+0

おかげと同じように動作させるためにODataのでプレ​​ーする必要があります - 違いはありませんでしたありませんが、私は私が望む方法でODATA作品を作るために管理してお答えします私が使ったものとの質問。私はODataのバグにこの境界を感じます。 – Tim

+0

うん、バウンスのように聞こえる、どんな場合でも外側選択の 'TOP'は悪いです。そして、その追加のORDER BYステートメント... – Nikita

答えて

4

私はこの問題は、ODataのは非常にスマートではないということです、そして間違った順序でクエリオプションを適用しました。以下のコードは、トップ、最初の[並べ替えを適用します。

private static IQueryable<Item> ApplyOptimizedOdataOptions(IQueryable<Item> origQuery, ODataQueryOptions<Item> options) 
{ 
    var defaultOdataQuerySettings = new ODataQuerySettings(); 
    if (options.Top != null && options.OrderBy != null) 
    { 
     // We can optimze this query. Apply the OrderBy first, then Top. 
     IQueryable results = options.OrderBy.ApplyTo(origQuery, defaultOdataQuerySettings); 
     results = options.Top.ApplyTo(results, defaultOdataQuerySettings); 
     results = options.ApplyTo(results, defaultOdataQuerySettings, AllowedQueryOptions.Top | AllowedQueryOptions.OrderBy); 

     return results as IQueryable<Item>; 
    } 

    return options.ApplyTo(origQuery, defaultOdataQuerySettings) as IQueryable<Item>; 
} 

私はこれのIQueryableを使用することによって生成された結果のSQL文を実行した場合:

:再注文するこれらのステートメント

SET STATISTICS TIME ON; 
// Run SQL here 
SET STATISTICS TIME OFF; 

をもたらしました

SQL Serverの実行時間:CPU時間= 0ミリ秒、経過時間= 1ミリ秒。

私は再オーダーしていない場合に比べて

SQL Serverの実行時間:CPU時間= 1213ミリ秒、経過時間= 20112ms。

〜20,000の速度向上。

+0

ありがとう。サーバー側でクエリをインターセプトしてソリューションを適用する場所を知っていますか? Jü[email protected] –

+0

- あなたは、Web APIを使用していると仮定すると、あなたのGETメソッドを使用すると、あなたの根底にあるのIQueryableにそれを適用する前に、あなたが望むようにあなたが操作できるパラメータとして「ODataQueryOptions オプション」を持っている必要があります。 – Tim

+0

私は 'OData 5.6.3'(' EntityFramework 6.1。3(EntityFrameworkDataService ) 'であり、実行前にクエリを書き換えるソリューションを探しています。どんな助けやヒントもありがとう。 –

0

実際には、orderbyはトップより早く適用され、トップが安定してシーンを作成する必要があります。これはsqlを実行するときと同じロジックです。常に上にorderby、またはデフォルトの順序でシナリオを設定する必要があります。トップを使用して、結果を得た後に注文してください。

関連する問題