gpt4 book ai didi

c# - 什么更快?结构数组或数据表

转载 作者:太空狗 更新时间:2023-10-29 23:04:22 25 4
gpt4 key购买 nike

我正在使用 LinqToSQL 处理来自 SQL Server 的数据,以将其转储到 iSeries 服务器以进行进一步处理。 More details on that here .

我的问题是处理这 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 <= monthEndDate.Date) && a.EquipmentID == vehicleKey
group b by c.Fuel into d
select new
{
isFuel = d.Key,
totalCost = d.Sum(b => 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;
}

我的想法是减少对数据库的查询数量以加快处理速度。如果 LINQ 对每条记录执行 SELECT,也许我需要先将每条记录加载到内存中。

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

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

最佳答案

我在您的代码中发现了几件事:

  1. 您针对“var vehicles”查询中的每个项目多次查询数据库,您可能希望重写该查询,以便减少需要的数据库查询。
  2. 当您不需要被查询实体的所有属性,或不需要该实体的子实体时,最好在 select 中使用匿名类型以提高性能。 . LINQ to SQL 将对此进行分析并从数据库中检索较少的数据。这样的选择可能如下所示:select new { a.VehicleId, a.Name }
  3. GetPartsAndOilCosts 中的查询可以通过计算 cost.totalCost * (1 + OVERHEAD_RATE) 来优化在 LINQ 查询中。这样查询就可以完全在数据库中执行,这应该会更快。
  4. 你正在做一个 Count()var vehicles 上查询,但您仅将其用于确定数组的大小。虽然 LINQ to SQL 会非常高效 SELECT count(*)查询它,它需要额外的往返数据库。除此之外(取决于您的隔离级别)您开始迭代查询的时间可以添加一个项目。在那种情况下,您的数组太小并且 ArrayIndexOutOfBoundsException将被抛出。您可以简单地使用 .ToArray()在查询或创建 List<EquipmentTable>并调用.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 上再次提问,但请记住将您的问题剥离到尽可能小的部分,因为阅读别人的烂摊子没有乐趣(我们没有得到报酬为了这) :-)祝你好运。

关于c# - 什么更快?结构数组或数据表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2418571/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com