Mar*_*gle 1 c# sql sql-server entity-framework join
连接两个表导致选择时间从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();
Run Code Online (Sandbox Code Playgroud)
结果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)))
Run Code Online (Sandbox Code Playgroud)
相比
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();
Run Code Online (Sandbox Code Playgroud)
结果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)))
Run Code Online (Sandbox Code Playgroud)
小智 7
你看到了所有这些:
((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)
.Where(t => t.LogType!= 4)
看起来像一个类型不匹配 - 让我猜,它不是数据库中的int.然后使用Equals方法.这是EF中的已知错误.说它应该没关系 - 此时你应该归结为很多条目,你的问题可能是日期时间比较的低效代码.
永远不要在比较的现场做一个功能.决不.它们会终止任何索引使用(除非有一个完全具有此功能的索引).始终重写查询以使所有函数都处于常量.
不是EF问题 - 一般的SQL初学者错误.
归档时间: |
|
查看次数: |
1954 次 |
最近记录: |