我目前有一个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) )
答案 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) )