我在 EF 拉一些实体时遇到了一些麻烦。有问题的实体有一大堆存在于 1 个表中的道具,但它也有一些与其他表相关的 ICollection。我已经放弃了加载整个对象图的想法,因为它的数据太多,而是让我的 Silverlight 客户端在需要详细信息时向我的 WCF 服务发送一个新请求。
在精简到 1 个表的东西之后,大约需要 8 秒来提取数据,然后再用 1 秒来 .ToList() (我希望这会小于 1 秒)。我正在使用秒表类进行测量。当我在 SQL 管理工作室中运行 SQL 查询时,它只需要几分之一秒,所以我很确定 SQL 语句本身不是问题。
这是我尝试查询数据的方式:
public List<ComputerEntity> FindClientHardware(string client)
{
long time1 = 0;
long time2 = 0;
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
// query construction always takes about 8 seconds, give or a take a few ms.
var entities =
DbSet.Where(x => x.CompanyEntity.Name == client); // .AsNoTracking() has no impact on performance
//.Include(x => x.CompanyEntity)
//.Include(x => x.NetworkAdapterEntities) // <-- using these 4 includes has no impact on SQL performance, but faster to make lists without these
//.Include(x => x.PrinterEntities) // I've also abandoned the idea of using these as I don't want the entire object graph (although it would be nice)
//.Include(x => x.WSUSSoftwareEntities)
//var entities = Find(x => x.CompanyEntity.Name == client); // <-- another test, no impact on performance, same execution time
stopwatch.Stop();
time1 = stopwatch.ElapsedMilliseconds;
stopwatch.Restart();
var listify = entities.ToList(); // 1 second with the 1 table, over 5 seconds if I use all the includes.
stopwatch.Stop();
time2 = stopwatch.ElapsedMilliseconds;
var showmethesql = entities.ToString();
return listify;
}
我假设使用 .Include 意味着急切加载,尽管它与我目前的情况无关,因为我只想要 1 个表的东西。此语句(在 SSMS 中执行速度超快)生成的 SQL 为:
SELECT
[Extent1].[AssetID] AS [AssetID],
[Extent1].[ClientID] AS [ClientID],
[Extent1].[Hostname] AS [Hostname],
[Extent1].[ServiceTag] AS [ServiceTag],
[Extent1].[Manufacturer] AS [Manufacturer],
[Extent1].[Model] AS [Model],
[Extent1].[OperatingSystem] AS [OperatingSystem],
[Extent1].[OperatingSystemBits] AS [OperatingSystemBits],
[Extent1].[OperatingSystemServicePack] AS [OperatingSystemServicePack],
[Extent1].[CurrentUser] AS [CurrentUser],
[Extent1].[DomainRole] AS [DomainRole],
[Extent1].[Processor] AS [Processor],
[Extent1].[Memory] AS [Memory],
[Extent1].[Video] AS [Video],
[Extent1].[IsLaptop] AS [IsLaptop],
[Extent1].[SubnetMask] AS [SubnetMask],
[Extent1].[WINSserver] AS [WINSserver],
[Extent1].[MACaddress] AS [MACaddress],
[Extent1].[DNSservers] AS [DNSservers],
[Extent1].[FirstSeen] AS [FirstSeen],
[Extent1].[IPv4] AS [IPv4],
[Extent1].[IPv6] AS [IPv6],
[Extent1].[PrimaryUser] AS [PrimaryUser],
[Extent1].[Domain] AS [Domain],
[Extent1].[CheckinTime] AS [CheckinTime],
[Extent1].[ActiveComputer] AS [ActiveComputer],
[Extent1].[NetworkAdapterDescription] AS [NetworkAdapterDescription],
[Extent1].[DHCP] AS [DHCP]
FROM
[dbo].[Inventory_Base] AS [Extent1]
INNER JOIN [dbo].[Entity_Company] AS [Extent2]
ON [Extent1].[ClientID] = [Extent2].[ClientID]
WHERE
[Extent2].[CompanyName] = @p__linq__0
这基本上是选择此表中的所有列,加入具有公司名称的第二个表,并使用 companyname == 方法的输入值的 where 子句进行过滤。我要提取的特定公司仅返回 75 条记录。
使用 .AsNoTracking() 禁用对象跟踪对执行时间的影响为零。
我还尝试了 Find 方法,它的执行时间完全相同。我尝试的下一件事是预先生成视图,以防出现问题。我首先使用代码,所以我使用了 EF 电动工具来执行此操作。
运行此查询的这段时间很长,对我的用户造成了太长的延迟。当我手写 SQL 代码并且不接触 EF 时,它超级快。关于我缺少什么的任何想法?
另外,可能相关或不相关,但由于我在无状态的 WCF 中执行此操作,我假设绝对没有任何内容被缓存?我的想法是,每个新调用都是第一次启动这个 WCF 服务库,因此没有预先存在的缓存。这是一个准确的假设吗?
更新 1
所以我在同一个单元测试中运行了两次这个查询来检查冷/热查询的事情。第一个查询正如预期的那样可怕,但第二个查询是闪电般快速地以 350 毫秒的速度完成整个查询。由于 WCF 是无状态的,对我的 WCF 服务的每次调用都会被视为第一个丑陋的慢查询吗?仍然需要弄清楚如何让第一个查询不糟糕。
更新 2
你知道我之前提到的那些预先生成的视图吗?嗯……我不认为他们被击中了。我在 EF-powertools 自动生成的 ReportingDbContext.Views.cs 文件中放置了一些断点,但它们从未被击中。再加上我看到的冷/热查询性能,这听起来很有意义。我需要在代码优先环境中使用 EF 电动工具预生成视图吗?