Linq中从复杂视图查询数据耗时过长问题求助
问题描述
尝试从复杂视图View_QuickSearch中查询数据时,实体化操作耗时长达4秒,具体代码如下:
// 1. Perform a Search by name on tbl_member var memberIDs = (from m in DC.tbl_Member where (m.FirstNameFiltered + ' ' + m.LastNameFiltered).Contains(filteredName) select m.MemberID).Take(10).ToList(); // 2. Get the members data from View_QuickSearch var members = (from m in DC.View_QuickSearch where memberIDs.Contains(m.MemberID) select m); // 3. Materialize the results members.ToList();
第一步从tbl_Member表按名称搜索获取ID耗时2秒,符合预期;第二步通过10个ID查询视图时,members.ToList()耗时4秒。但将Visual Studio调试得到的SQL语句在SSMS中执行,仅需数毫秒即可返回结果:
SELECT [t0].[MemberID], [t0].[fullName], [t0].[fullNameFiltered], [t0].[Mobile], [t0].[NationalID], [t0].[Job], [t0].[Company], [t0].[EDUClass], [t0].[AttendanceChurch], [t0].[FamilyChurch] FROM [dbo].[View_QuickSearch] AS [t0] WHERE [t0].[MemberID] IN (756, 969, 1349, 1390, 1486, 1900, 2234, 2697, 2852, 3286)
已排除视图本身、查询语句及索引问题,寻求耗时问题的解决办法。
解决办法
合并两次查询,减少数据库往返并优化执行计划
将两次查询合并为单次Linq查询,让EF生成关联SQL语句,避免两次数据库请求的开销,同时让数据库生成更高效的执行计划:var members = (from m in DC.View_QuickSearch join member in DC.tbl_Member on m.MemberID equals member.MemberID where (member.FirstNameFiltered + ' ' + member.LastNameFiltered).Contains(filteredName) select m).Take(10).ToList();使用原生SQL直接执行视图查询
绕过Linq to EF的映射层,直接执行原生SQL,避免实体映射可能带来的额外开销:// 安全拼接ID(ID来自数据库查询,无注入风险) var memberIdsStr = string.Join(",", memberIDs); var sql = @"SELECT [MemberID], [fullName], [fullNameFiltered], [Mobile], [NationalID], [Job], [Company], [EDUClass], [AttendanceChurch], [FamilyChurch] FROM [dbo].[View_QuickSearch] WHERE [MemberID] IN ({0})"; var members = DC.View_QuickSearch.FromSqlRaw(string.Format(sql, memberIdsStr)).ToList();若ID来自用户输入,需使用参数化查询避免SQL注入:
var parameters = memberIDs.Select((id, idx) => new SqlParameter($"@id{idx}", id)).ToArray(); var placeholders = string.Join(",", parameters.Select(p => p.ParameterName)); var sql = $"SELECT * FROM [dbo].[View_QuickSearch] WHERE [MemberID] IN ({placeholders})"; var members = DC.View_QuickSearch.FromSqlRaw(sql, parameters).ToList();关闭EF实体跟踪功能
若无需修改查询结果,关闭实体跟踪可减少EF维护状态的开销:var members = (from m in DC.View_QuickSearch.AsNoTracking() where memberIDs.Contains(m.MemberID) select m).ToList();检查视图实体的映射配置
确认View_QuickSearch对应的实体类是否存在未使用的导航属性或冗余映射。多余的导航属性可能导致EF在查询时产生额外的初始化或加载开销,可移除这些不必要的配置。验证EF实际执行的SQL
通过EF日志功能确认实际执行的SQL与调试看到的是否一致,排除参数化或上下文状态导致的差异:DC.Database.Log = message => System.Diagnostics.Debug.WriteLine(message);查看输出日志,对比实际执行的SQL与SSMS中运行的语句是否完全匹配。
内容的提问来源于stack exchange,提问作者John Risk
相关产品推荐
相关产品推荐

