表加入Entity Framework的性能问题

加入两个表会导致选择时间从330秒增加到40秒。 将要连接的表仅包含ID和文本。 加入两张桌子时,我没想到选择时间会增加8倍。 我的JOIN有什么问题或者这是正常的SQL Server行为吗?

主表填充了3500万条记录,以查看在达到10 GB的SQL Server Express限制时它的执行情况。 在字段LogTimeStamp和字段LogType上创建了另一个索引。

连接表的内容:

表格Logtypes的内容

var queryList = messages .Join(types, type => type.LogType, typeText => typeText.LogType, (msg, msgType) => new { msg.LogID, msg.LogTimeStamp, msg.LogUser, msg.LogType, msgType.LogTypeName, msg.LogMessage }) .Where(t => System.Data.Entity.DbFunctions.TruncateTime(t.LogTimeStamp) >= fromDate) .Where(t => System.Data.Entity.DbFunctions.TruncateTime(t.LogTimeStamp)  t.LogType != 4) .OrderBy(m => m.LogID) .ToList(); 

结果SQL

 SELECT 1 AS [C1], [Extent1].[LogID] AS [LogID], [Extent1].[LogTimeStamp] AS [LogTimeStamp], [Extent1].[LogUser] AS [LogUser], [Extent1].[LogType] AS [LogType], [Extent2].[LogTypeName] AS [LogTypeName], [Extent1].[LogMessage] AS [LogMessage] FROM [dbo].[AuditTrailMessages] AS [Extent1] INNER JOIN [dbo].[AuditTrailLogTypes] AS [Extent2] ON [Extent1].[LogType] = [Extent2].[LogType] WHERE ((convert (datetime2, convert(varchar(255), [Extent1].[LogTimeStamp], 102) , 102)) >= @p__linq__0) AND ((convert (datetime2, convert(varchar(255), [Extent1].[LogTimeStamp], 102) , 102)) <= @p__linq__1) AND ( NOT ((4 = CAST( [Extent1].[LogType] AS int)) AND ( CAST( [Extent1].[LogType] AS int) IS NOT NULL))) 

相比

 var queryList = messages .Where(t => System.Data.Entity.DbFunctions.TruncateTime(t.LogTimeStamp) >= fromDate) .Where(t => System.Data.Entity.DbFunctions.TruncateTime(t.LogTimeStamp)  t.LogType != 4) .OrderBy(m => m.LogID) .ToList(); 

结果SQL

 SELECT [Extent1].[LogID] AS [LogID], [Extent1].[LogTimeStamp] AS [LogTimeStamp], [Extent1].[LogUser] AS [LogUser], [Extent1].[LogMessage] AS [LogMessage], [Extent1].[LogType] AS [LogType] FROM [dbo].[AuditTrailMessages] AS [Extent1] WHERE ((convert (datetime2, convert(varchar(255), [Extent1].[LogTimeStamp], 102) , 102)) >= @p__linq__0) AND ((convert (datetime2, convert(varchar(255), [Extent1].[LogTimeStamp], 102) , 102)) <= @p__linq__1) AND ( NOT ((4 = CAST( [Extent1].[LogType] AS int)) AND ( CAST( [Extent1].[LogType] AS int) IS NOT NULL))) 

你看到了所有这些:

((convert(datetime2,convert(varchar(255),[Extent1]。[LogTimeStamp],102)

他们很坏。 特别糟糕。 他们基本上说“不要使用索引,进行全表扫描”。

对你说:

t => System.Data.Entity.DbFunctions.TruncateTime(t.LogTimeStamp)> = fromDate

这不好。 它不是必需的。 日期中的任何时间戳都大于或等于每个定义的日期,并且小于下一个日期。

所以:

t => System.Data.Entity.DbFunctions.TruncateTime(t.LogTimeStamp)> = fromDate

变成

t => t.LogTimeStamp> = fromDate

t => System.Data.Entity.DbFunctions.TruncateTime(t.LogTimeStamp)<= toDate

变成

t => t.LogTimeStamp

.Where(t => t.LogType!= 4)

看起来像一个类型不匹配 – 让我猜,它不是数据库中的int。 然后使用Equals方法。 这是EF中的一个已知错误。 BUt它应该没关系 – 此时你应该归结为相当多的条目,你的问题可能是日期时间比较的超低效代码。

永远不要在比较的现场做一个function。 决不。 它们会终止任何索引使用(除非有一个完全具有此function的索引)。 始终重写查询以使所有函数都处于常量。

不是EF问题 – 一般的SQL初学者错误。