繁体   English   中英

实体框架的表联接性能问题

[英]Table Join performance issue with 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) <= toDate)
    .Where(t => 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) <= toDate)
    .Where(t => 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 <toDate.AddDays(1)

在哪里(t => t.LogType!= 4)

看起来像类型不匹配-让我猜,它不是数据库中的int。 然后使用等于方法。 这是EF中的已知错误。 但没关系-在这一点上,您应该输入很多条目,您的问题可能是日期时间比较的代码效率低下。

永远不要在比较的现场方面发挥作用。 决不。 它们会杀死任何索引使用(除非存在完全具有此功能的索引)。 始终重写查询以使所有函数都处于常数。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM