[英]Bad OData Performance with Entity Framework and Top and OrderBy
我正在使用OData 5.8.0和EntityFramework 6.1.3,查詢:
&$filter=fieldA eq 'ABCDEFG'&$skip=0&$top=10&$orderby=fieldB desc
結果是:
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
對於大量的字段A,大約需要20秒才能在DB上運行。
如果我使用相同的LINQ:
var newList = table.Where(f => f.fieldA == 'ABCDEFG').OrderByDescending(f => f.fieldB).Take(10).Skip(0).ToList();
結果是:
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
運行需要120毫秒。
如何強制OData使用相同的表達式(即不在外部語句中使用TOP)?
我發現這個問題是OData不是很聰明,並且以錯誤的順序應用查詢選項。 下面的代碼首先應用orderBy,然后應用頂部:
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 ms,經過的時間= 20112ms。
速度提升約20,000倍。
實際上,orderby應該比top早應用,以便top穩定並創建場景。運行sql時,這是相同的邏輯,總是應該有一個top帶有orderby,或者按默認順序排列,在這種情況下,您應該只使用top,得到結果后再訂購。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.