什么更快?结构体数组或数据表

2024-04-02

我正在使用 LinqToSQL 处理来自 SQL Server 的数据,并将其转储到 iSeries 服务器中以进行进一步处理。更多详细信息请点击此处 https://stackoverflow.com/questions/2410466/speeding-up-queries-with-linq.

我的问题是处理这 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 编程)。所以我猜我在做一些愚蠢的事情。你能帮我解决我的愚蠢问题(至少解决这个问题)吗?

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


我在您的代码中发现了一些内容:

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

对第一点的一些额外解释。你在这里所做的有点像这样:

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 再次询问,但请记住将你的问题精简到尽可能小的程度,因为阅读别人的混乱内容并不有趣(我们不会为此获得报酬) :-) 祝你好运。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么更快?结构体数组或数据表 的相关文章

随机推荐