表加入Entity Framework的性能问题
加入两个表会导致选择时间从330秒增加到40秒。 将要连接的表仅包含ID和文本。 加入两张桌子时,我没想到选择时间会增加8倍。 我的JOIN有什么问题或者这是正常的SQL Server行为吗?
主表填充了3500万条记录,以查看在达到10 GB的SQL Server Express限制时它的执行情况。 在字段LogTimeStamp和字段LogType上创建了另一个索引。
连接表的内容:
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初学者错误。