【发布时间】:2017-07-21 20:30:32
【问题描述】:
总结一下这个问题,我有一个实体框架根据我的 LINQ 查询生成的查询,该查询将两个表连接到一个值上,其中一个存储为 UNIQUEIDENTIFIER,另一个存储为(Nullable)VARCHAR。
由于两种不同的数据类型,我必须在 LINQ 查询中对 GUID 值调用 ToString()。
生成的 SQL 代码虽然令人钦佩,但最终速度很慢,因为它不只是比较两列(就像我在标准 SQL 查询中可能那样),它尝试转换一个表中的 UNIQUEIDENTIFIER 列并尝试赶上 Nulls。
如果我采用 Entity Framework 生成的查询并简单地删除它尝试进行转换的部分,则当有大约 300 条记录要返回时,查询将从 30 秒变为 0 秒。
所以,假设我坚持使用具有不同数据类型的表来存储相同的值,我想知道我是否可以告诉 Entity Framework 不要尝试在此列上进行转换而直接执行上比较。 (我们一直在查询和存储过程中这样做,它工作得很好而且速度很快。)
如果没有办法告诉实体框架,在这个特定的实例中,我是否只需要编写一个存储过程并调用它,而不是尝试在 LINQ 中编写查询?
这是为用户返回通知的方法。
var notifications = from un in _context.UserNotifications
join n in _context.Notifications on un.NotificationId equals n.Id
join r in _context.Referrals on n.txt_assess_seq_no equals r.seq_no.ToString()
where un.UserId == userId & !un.IsRead
orderby n.create_timestamp descending
select n;
这给了我想要的结果,但是由于 Notifications.txt_assess_seq_no(表中的 VARCHAR)和 Referrals.seq_no(UNIQUIDENTIFIER)的加入,Entity Framework 生成的 SQL 查询很慢。
这是生成的 SQL:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM (SELECT [Extent1].[UserId] AS [UserId], [Extent2].[txt_assess_seq_no] AS [txt_assess_seq_no]
FROM [dbo].[UserNotifications] AS [Extent1]
INNER JOIN [dbo].[ContactDetails] AS [Extent2] ON [Extent1].[NotificationId] = [Extent2].[seq_no]
WHERE [Extent1].[IsRead] = 0 ) AS [Filter1]
INNER JOIN [dbo].[Referrals] AS [Extent3] ON ([Filter1].[txt_assess_seq_no] = (LOWER( CAST( [Extent3].[seq_no] AS nvarchar(max))))) OR (([Filter1].[txt_assess_seq_no] IS NULL) AND (LOWER( CAST( [Extent3].[seq_no] AS nvarchar(max))) IS NULL))
WHERE [Filter1].[UserId] = 'USER ID (GUID) AS STRING'
) AS [GroupBy1]
如果我只是改变这一行:
INNER JOIN [dbo].[Referrals] AS [Extent3] ON ([Filter1].[txt_assess_seq_no] = (LOWER( CAST( [Extent3].[seq_no] AS nvarchar(max))))) OR (([Filter1].[txt_assess_seq_no] IS NULL) AND (LOWER( CAST( [Extent3].[seq_no] AS nvarchar(max))) IS NULL))
到:
([Filter1].[txt_assess_seq_no] = [Extent3].[seq_no])
它超级快,正是我想要的,但我不太确定如何到达那里。我想保持用 LINQ 编写,但如果我只需要使用存储过程或一些老式 SQL 代码,我会这样做。
任何想法或建议将不胜感激!
【问题讨论】:
-
你真正应该做的是修复表格。当您混合数据类型时,您正在为性能问题做好准备。
-
我知道,但在这种情况下,由于您可能不喜欢听到的原因,这是不可能的。我确实提到假设这是不可能的,你有什么建议吗?不过,我非常感谢您的回答!
-
嗯,发生的事情是 EF 意识到数据类型不同并进行了显式转换。您的代码只是在进行隐式转换。除了它创建的许多 sql 对性能来说很糟糕之外,我对 EF 知之甚少。
-
你很幸运。隐式转换可能会导致一些严重的性能问题。但是 EF 生成的转换代码并没有那么糟糕。抱歉,我无法帮助您处理 EF 的问题。希望有人能过来帮忙。
-
隐式转换与显式转换相反。 Uniqueidintifier 比字符串具有更高的优先级,因此如果没有明确的 guid 转换为字符串,您会得到相反的结果。
标签: sql-server asp.net-mvc entity-framework linq