更新3:根据此公告,EF团队已在EF6 alpha 2中解决了此问题。
更新2:我已经提出了解决此问题的建议。要投票,请转到此处。
考虑一个带有一个非常简单的表的SQL数据库。
CREATE TABLE Main (Id INT PRIMARY KEY)
我用10,000条记录填充表。
WITH Numbers AS
(
SELECT 1 AS Id
UNION ALL
SELECT Id + 1 AS Id FROM Numbers WHERE Id <= 10000
)
INSERT Main (Id)
SELECT Id FROM Numbers
OPTION (MAXRECURSION 0)
我为该表构建EF模型,并在LINQPad中运行以下查询(我使用的是“ C#语句”模式,因此LINQPad不会自动创建转储)。
var rows =
Main
.ToArray();
执行时间约为0.07秒。现在,我添加了Contains运算符并重新运行查询。
var ids = Main.Select(a => a.Id).ToArray();
var rows =
Main
.Where (a => ids.Contains(a.Id))
.ToArray();
这种情况下的执行时间为20.14秒(慢288倍)!
最初,我怀疑为查询发出的T-SQL需要花费更长的时间才能执行,因此我尝试将其从LINQPad的SQL窗格中剪切和粘贴到SQL Server Management Studio中。
SET NOCOUNT ON
SET STATISTICS TIME ON
SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Primary] AS [Extent1]
WHERE [Extent1].[Id] IN (1,2,3,4,5,6,7,8,...
结果是
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 88 ms.
接下来,我怀疑是LINQPad引起了问题,但是无论是在LINQPad还是在控制台应用程序中运行,其性能都是相同的。
因此,看来问题出在实体框架内。
我在这里做错什么了吗?这是我的代码中时间紧迫的部分,因此我可以做些什么来提高性能吗?
我正在使用Entity Framework 4.1和Sql Server 2008 R2。
更新1:
在下面的讨论中,存在一些有关是否在EF构建初始查询时或在解析回接收到的数据时发生延迟的问题。为了对此进行测试,我运行了以下代码,
var ids = Main.Select(a => a.Id).ToArray();
var rows =
(ObjectQuery<MainRow>)
Main
.Where (a => ids.Contains(a.Id));
var sql = rows.ToTraceString();
这迫使EF生成查询而不对数据库执行查询。结果是此代码需要大约20秒的时间才能运行,因此似乎几乎所有时间都花在了构建初始查询上。
然后把CompiledQuery救出来?并不是那么快... CompiledQuery要求传递到查询中的参数是基本类型(int,string,float等)。它不接受数组或IEnumerable,因此我不能将其用于ID列表。
var qry = Main.Where (a => ids.Contains(a.Id)); var rows = qry.ToArray();
查看查询的哪部分花费时间?