什么更快? 结构数组或DataTable

我使用LinqToSQL处理来自SQL Server的数据,将其转储到iSeries服务器中进行进一步处理。 关于这里的更多细节 。

我的问题是处理这350行数据需要大约1.25分钟。 我仍在尝试从SQL Server Profiler中解析结果,但是有一大堆查询正在运行。 以下是我正在做的事情的更多细节:

using (CarteGraphDataDataContext db = new CarteGraphDataDataContext()) { var vehicles = from a in db.EquipmentMainGenerals join b in db.EquipmentMainConditions on a.wdEquipmentMainGeneralOID equals b.wdEquipmentMainGeneralOID where b.Retired == null orderby a.VehicleId select a; et = new EquipmentTable[vehicles.Count()]; foreach (var vehicle in vehicles) { // Move data to the array // Rates GetVehcileRates(vehicle.wdEquipmentMainGeneralOID); // Build the costs accumulators GetPartsAndOilCosts(vehicle.VehicleId); GetAccidentAndOutRepairCosts(vehicle.wdEquipmentMainGeneralOID); // Last Month's Accumulators et[i].lastMonthActualGasOil = GetFuel(vehicle.wdEquipmentMainGeneralOID) + Convert.ToDecimal(oilCost); et[i].lastMonthActualParts = Convert.ToDecimal(partsCost); et[i].lastMonthActualLabor = GetLabor(vehicle.VehicleId); et[i].lastMonthActualOutRepairs = Convert.ToDecimal(outRepairCosts); et[i].lastMonthActualAccidentCosts = Convert.ToDecimal(accidentCosts); // Move more data to the array i++; } } 

Get方法看起来类似于:

 private void GetPartsAndOilCosts(string vehicleKey) { oilCost = 0; partsCost = 0; using (CarteGraphDataDataContext db = new CarteGraphDataDataContext()) { try { var costs = from a in db.WorkOrders join b in db.MaterialLogs on a.WorkOrderId equals b.WorkOrder join c in db.Materials on b.wdMaterialMainGeneralOID equals c.wdMaterialMainGeneralOID where (monthBeginDate.Date <= a.WOClosedDate && a.WOClosedDate  b.Cost) }; foreach (var cost in costs) { if (cost.isFuel == 1) { oilCost = (double)cost.totalCost * (1 + OVERHEAD_RATE); } else { partsCost = (double)cost.totalCost * (1 + OVERHEAD_RATE); } } } catch (InvalidOperationException e) { oilCost = 0; partsCost = 0; } } return; } 

我在这里的想法是减少对DB的查询数量,以加快处理速度。 如果LINQ为每条记录执行SELECT,则可能需要先将每条记录加载到内存中。

我仍然认为自己是C#和OOP的初学者(我主要在iSeries上进行RPG编程)。 所以我猜我做的事情很愚蠢。 你能帮助我解决我的愚蠢问题(至少在这个问题上)吗?

更新:我想我会回来告诉你我发现了什么。 看起来数据库的设计很差。 无论LINQ在后台生成什么,它都是非常低效的代码。 我不是说LINQ不好,这对这个数据库来说不好。 我转换为快速抛出.XSD设置,处理时间从1.25分钟到15秒。 一旦我进行了适当的重新设计,我只能猜测我会再缩短几秒钟。 谢谢大家的评论。 我会在更好的数据库上再次尝试LINQ。

我在你的代码中发现了一些东西:

  1. 您对“var vehicles”查询中的每个项目多次查询数据库,您可能希望重写该查询,以便需要较少的数据库查询。
  2. 如果您不需要查询实体的所有属性,或者需要该实体的子实体,那么在您的select使用匿名类型的性能会更好。 LINQ to SQL将对此进行分析并从数据库中检索较少的数据。 这样的选择可能如下所示: select new { a.VehicleId, a.Name }
  3. 可以通过将计算cost.totalCost * (1 + OVERHEAD_RATE)放在LINQ查询中来优化GetPartsAndOilCosts中的查询。 这样查询就可以在数据库中完全执行,这样可以使查询更快。
  4. 您正在对var vehicles查询执行Count() ,但您只能使用它来确定数组的大小。 虽然LINQ to SQL将对它进行非常有效的SELECT count(*)查询,但它需要额外的数据库往返。 除此之外(取决于您的隔离级别),您开始迭代查询的时间可以添加项目。 在这种情况下,您的数组太小,将抛出ArrayIndexOutOfBoundsException 。 您可以在查询上使用.ToArray()或创建List并在其上调用.ToArray() 。 这通常会足够快,特别是当您在此集合中只有380个项目时,它肯定比向数据库额外往返(计数)更快。
  5. 正如您可能已经预料到的那样,数据库查询量是实际问题。 在struct array或DataTable之间切换不会有太大的不同。
  6. 在尽可能多地优化查询之后,开始分析剩余的查询(使用SQL事件探查器)并使用索引调整向导优化这些查询。 它将为您提出一些新的索引,这可以大大加快速度。

点#1的一点额外解释。 你在这里做的有点像这样:

 var query = from x in A select something; foreach (var row in query) { var query2 = from y in data where y.Value = row.Value select something; foreach (var row2 in query2) { // do some computation. } } 

您应该尝试完成的是删除query2子查询,因为它在顶部查询的每一行上执行。 所以你最终会得到这样的东西:

 var query = from x in A from y in B where x.Value == y.Value select something; foreach (var row in query) { } 

当然这个例子很简单,在现实生活中它变得非常复杂(正如你已经注意到的那样)。 在你的情况下,因为你有多个’子查询’。 你可能需要一些时间才能做到这一点,尤其是你缺乏LINQ to SQL的知识(就像你自己说的那样)。

如果你无法弄清楚,你可以随时在Stackoverflow再次询问,但请记住将问题排除在最小的可能之外,因为阅读某人的混乱并不是一件好事(我们没有得到报酬) :-) 祝好运。