更新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的某个地方。
我这里做错了什么吗?这是我的代码的关键部分,所以是否有什么我可以做来加速性能?
我正在使用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秒才能运行,因此看起来几乎所有时间都用在了构建初始查询上。
那么编译查询有救吗?不要那么快...... 编译查询要求传递给查询的参数为基本类型(int、string、float 等)。它不接受数组或 IEnumerable,所以我不能将其用于 ID 列表。
var qry = Main.Where(a => ids.Contains(a.Id)); var rows = qry.ToArray();
来查看查询的哪个部分需要时间吗? - Andrew Cooper10 <= ids <= 500
? - Kris Ivanovparent._recompileRequired =()=> true;
。糟糕! - jocull