OData $ top和PageSize对Web API性能没有影响

时间:2018-01-11 23:00:32

标签: javascript c# sql-server entity-framework odata

我目前有一个ASP.net WebApplication的Web API,用于查询SQL Server 2008 R2中所有测试数据(约500k行)的视图,这些数据在Web API中被引用实体框架

public class TestDataController : ApiController
{
    TeraDiodeEntities dc = new TeraDiodeEntities();
    // GET api/<controller>

    [EnableQuery]
    public IQueryable<KPI_AllData_View> Get()
    {
        return dc.KPI_AllData_View;

    }
}

过滤数据具有可接受的性能,这是我用来调试Web API的客户端代码:

    function getdata() {
        startTime = new Date();
        $.ajax({
            url: "../api/TestData?$filter=DeviceTypeID eq 2 and DevicePartNumberID eq 74 and TestDateSmall gt 2017-01-01T23:59:59.99Z",
            type: 'GET',
            dataType: 'json',
            success: function (data, textStatus, xhr) {
                endTime = new Date();
                var timeDiff = endTime - startTime;
                timeDiff /= 1000;
                var seconds = Math.round(timeDiff);
                console.log(seconds + " seconds");
                console.log(data);
            },
            error: function (xhr, textStatus, errorThrown) {
                console.log('Error in Operation');
            }
        });
    }

此查询:

  

“../ api / TestData?$ filter = DeviceTypeID eq 2和DevicePartNumberID eq   74和TestDateSmall gt 2017-01-01T23:59:59.99Z“

在21秒内返回78575行

与TSQL相比:

SELECT  *
  FROM [Teradiode].[dbo].[KPI_AllData_View]
  where DeviceTypeID = 2 and DevicePartNumberID = 74 and TestDateSmall > '1/1/17'

对于相同的78575行需要13秒

我理解从开销将数据转换为json增加的时间增加了几秒钟。我最大的问题是在Odata中选择前N行:

  

“../ api / TestData?$ filter = DeviceTypeID eq 2和DevicePartNumberID eq   74和TestDateSmall gt 2017-01-01T23:59:59.99Z&amp; $ top = 100“

该查询大约需要16秒才能返回100行,我相信我保存的额外时间只是来自较小的有效负载。

使用TSQL执行相同的操作:

SELECT  top 100 *
  FROM [Teradiode].[dbo].[KPI_AllData_View]
  where DeviceTypeID = 2 and DevicePartNumberID = 74 and TestDateSmall > '1/1/17'

在1秒内返回100行(它也可以在5秒内完成10000行)

我的猜测是,在SQL数据库上的Filter操作完成之后,OData才会占据前100行。我也尝试在过滤器之前移动“$ top100”并最终获得相同的结果。

我也尝试将Web API的PageSize设置为100,如下所示:

[EnableQuery(PageSize =100)]

但这对性能没有影响。

任何人都知道我可能会错过或做错什么可能导致如此大的性能损失?或者这是Odata的缺点吗?

感谢。

编辑1: 我捕获了从Entity Framework生成的SQL,为了便于阅读,我还用*替换了列名。它也按我省略的所有列排序。它看起来似乎没有得到适当的优化,因为它几乎可以选择所有的东西3次。

DECLARE @p__linq__0 BIGINT = 74 
DECLARE @p__linq__1 INT = 100 

SELECT TOP (@p__linq__1) * 
FROM   (SELECT * 
    FROM   (SELECT * 
            FROM   [dbo].[kpi_alldata_view] AS [KPI_AllData_View]) AS 
           [Extent1] 
    WHERE  ( [Extent1].[devicepartnumberid] = @p__linq__0 ) 
           AND ( [Extent1].[testdatesmall] > 
                 CONVERT(DATETIME2, '2017-01-01 18:59:59.9900000', 
                     121) )) AS [Project1]
ORDER BY [Project1].[testdatesmall] DESC, 
     [Project1].[devicepartnumber] ASC, 
     [Project1].[devicepartnumberid] ASC, 
     [Project1].[devicepartnumberprefix] ASC, 
     [Project1].[devicetypeid] ASC, 
     [Project1].[displayorder] ASC, 
     [Project1].[exclude] ASC, 
     [Project1].[fiitemno] ASC, 
     [Project1].[hold] ASC, 
     [Project1].[job] ASC, 
     [Project1].[lotid] ASC, 
     [Project1].[lotquantity] ASC, 
     [Project1].[maxvalue] ASC, 
     [Project1].[measurementname] ASC, 
     [Project1].[minvalue] ASC, 
     [Project1].[operatorid] ASC, 
     [Project1].[operatorinitials] ASC, 
     [Project1].[operatorname] ASC, 
     [Project1].[productionmode] ASC, 
     [Project1].[productionmodeid] ASC, 
     [Project1].[reason] ASC, 
     [Project1].[recievernumber] ASC, 
     [Project1].[rev] ASC, 
     [Project1].[reviewer] ASC, 
     [Project1].[serialnumber] ASC, 
     [Project1].[stationdescription] ASC, 
     [Project1].[stationid] ASC, 
     [Project1].[stationname] ASC, 
     [Project1].[testdataid] ASC, 
     [Project1].[testdate] ASC, 

编辑2:

似乎多个选择都很好,它的排序杀死了性能。现在我只需要阻止它订购所有东西。

编辑3:

通过阅读这篇文章后禁用“EnsureStableOrdering”(Entity framework with OData(Web API) is sending Order By clause By default to Sql Query

,我加快了速度
[EnableQuery(EnsureStableOrdering = false)]

现在返回100行只需要一秒或更短时间。排序很慢,但这只是我索引的问题,而不是OData。

现在,生成的SQL看起来像这样:

DECLARE @p__linq__0 BIGINT = 74 
DECLARE @p__linq__1 INT = 100 

SELECT TOP (@p__linq__1) * 
FROM   (SELECT * 
    FROM   [dbo].[kpi_alldata_view] AS [KPI_AllData_View]) AS [Extent1] 
WHERE  ( [Extent1].[devicepartnumberid] = @p__linq__0 ) 
   AND ( [Extent1].[testdatesmall] > 
         CONVERT(DATETIME2, '2017-01-01 18:59:59.9900000', 
             121) ) 

1 个答案:

答案 0 :(得分:1)

答案在帖子中,但我也会在这里添加。

编辑3:

通过阅读这篇文章后禁用“EnsureStableOrdering”(Entity framework with OData(Web API) is sending Order By clause By default to Sql Query

,我加快了速度
[EnableQuery(EnsureStableOrdering = false)]

现在返回100行只需要一秒或更短时间。排序很慢,但这只是我索引的问题,而不是OData。

现在,生成的SQL看起来像这样:

DECLARE @p__linq__0 BIGINT = 74 
DECLARE @p__linq__1 INT = 100 

SELECT TOP (@p__linq__1) * 
FROM   (SELECT * 
    FROM   [dbo].[kpi_alldata_view] AS [KPI_AllData_View]) AS [Extent1] 
WHERE  ( [Extent1].[devicepartnumberid] = @p__linq__0 ) 
   AND ( [Extent1].[testdatesmall] > 
         CONVERT(DATETIME2, '2017-01-01 18:59:59.9900000', 
             121) )