c# - Linq 查询处理结果的时间太长
问题描述
我有 3 张桌子
- ERP入口
- ERPEntryType
- ERPApp
我正在尝试使用以下查询从这 3 个表中获取数据:.. 表 ERPApp 与其他 2 个表处于不同的上下文中,这就是我使用 2 个查询的原因
var res = (from s in ERPDB.ERPEntrys
join t in ERPDB.ERPEntryTypes
on s.EntryTypeID equals t.EntryTypeID
where s.UserIDAdded == '250176'
select new {s.EntryTypeID, s.DateAdded, t.EntryTypeName, s.AppID }).OrderByDescending(d => d.DateAdded).Take(10).ToArray();
var erpResult = (from a in APPDB.ERPApps.AsEnumerable()
join b in res on a.AppId equals b.AppId
select new ERPInfo
{
EntryId = b.EntryID,
EntryType = b.EntryTypeName,
ERPApp = a.ApplicationName,
DateAdded = b.DateAdded
}).ToList();
我得到了想要的结果,但是第二个查询需要将近 4 分钟的时间来处理并将结果返回到变量 erpResult 中......关于如何解决这个性能问题的任何帮助?
解决方案
首先,答案:
var res = (from s in ERPDB.ERPEntries
join t in ERPDB.ERPEntryTypes
on s.EntryTypeID equals t.EntryTypeID
where s.UserIdAdded == "250176"
select new { s.EntryID, s.EntryTypeID, s.DateAdded, t.EntryTypeName, s.AppId })
.OrderByDescending(d => d.DateAdded).Take(10).ToArray();
/* Which immediately executes:
exec sp_executesql N'SELECT TOP (10) [t0].[EntryID], [t0].[EntryTypeID],
[t0].[DateAdded], [t1].[EntryTypeName], [t0].[AppId]
FROM [dbo].[ERPEntry] AS [t0]
INNER JOIN [dbo].[ERPEntryType] AS [t1] ON [t0].[EntryTypeID] = [t1].
[EntryTypeID]
WHERE [t0].[UserIdAdded] = @p0
ORDER BY [t0].[DateAdded] DESC',N'@p0 varchar(8000)',@p0='250176'
*/
// Get the distinct AppID values in res
// Executes in memory
var distinctApps = (from r in res select r.AppId).Distinct();
// Query APPDB with the distinct values
var matchingApps = (from a in APPDB.ERPApps where distinctApps
.Contains(a.AppId) select new { a.AppId, a.ApplicationName }).ToArray();
/* Which immediately executes this efficient query:
exec sp_executesql N'SELECT [t0].[AppId], [t0].[ApplicationName]
FROM [dbo].[ERPApp] AS [t0]
WHERE [t0].[AppId] IN (@p0, @p1, @p2, @p3)',N'@p0 bigint,@p1 bigint,@p2
bigint,@p3 bigint',@p0=101,@p1=123,@p2=125,@p3=129
*/
var erpResultWithAppNames = (from a in matchingApps
join b in res on a.AppId equals b.AppId
select new
{
EntryId = b.EntryID,
EntryType = b.EntryTypeName,
ERPApp = a.ApplicationName,
DateAdded = b.DateAdded
}).ToList();
额外说明:
正如评论中已经提到的,.AsEnumerable()
对APPDB.ERPApps
表的调用导致整个表作为对象加载到内存中。
事实:
您必须将 25.000 行加载到内存中(并将它们转换为对象),
您不仅要加载 25.000 行。您正在加载 25.000 x 173 个单元格并创建 25.000 个对象,每个对象具有 173 个字段。
如果您可以只加载您需要的两个字段(AppId 和 ApplicationName)而不是所有 173 个字段(以及它们拥有的任何数据),那么性能将会提高,但考虑到您要实现的目标仍然效率低下。
当前的性能问题部分是由于将整个表及其所有 173 个字段传输到您的服务器,部分是由于将所有这些行映射到对象和字段映射到属性。每一项的影响都可以作为进一步的研究来衡量。
LINQ 到 SQL。使用 SqlProfiler 检查时:
from a in APPDB.ERPApps.AsEnumerable() join b ...
// PROFILED QUERY:
SELECT [t0].[AppId], [t0].[ApplicationName], [t0].[Field1], [t0].[Field2],
[t0].[Field3], [t0].[Field4], [t0].[Field5], [t0].[Field6], [t0].[Field7],
[t0].[Field8], [t0].[Field9], ... ... ... ... [t0].[Field176], [t0].[Field173],
FROM [dbo].[ERPApp] AS [t0]
但:
var erpResult = (from a in APPDB.ERPApps
select new { AppId = a.AppId, ApplicationName = a.ApplicationName }
).ToArray();
// PROFILED QUERY:
SELECT [t0].[AppId], [t0].[ApplicationName]
FROM [dbo].[ERPApp] AS [t0]
推荐阅读
- ios - Swift Realm:线程安全并发读写索引越界
- mysql - 有没有办法避免由于同一张表中的共享锁提升而导致死锁?
- celery - Celery 活动任务持久化
- html - 如何使用 Jinja2 删除移动和桌面中重复的模板继承?
- node.js - '@' SyntaxError: 无效或意外的令牌
- r - r中的多次模拟
- wordpress - 显示特定类别并由管理员管理
- apache-kafka - SerializationException:IntegerDeserializer 接收的数据大小不是 4
- python - 如何在 QWebEnginePage-pyqt5 中使用 POST 方法打开 URL
- java - 背景图像会降低 recyclerview 的性能