【问题标题】:Why are 700k database rows taking over 15 seconds to load into memory?为什么 700k 数据库行需要超过 15 秒才能加载到内存中?
【发布时间】:2014-01-22 11:40:15
【问题描述】:

使用 C# 和 .NET 3.5 以及 ADO 连接或 OLEDB 连接,用 700k 行(每行 3 列)填充 DataTable 或 DataSet,需要 15 秒以上。

在 DB 上执行实际的 select 语句需要不到一秒钟的时间。数据库与查询它的机器位于不同的机器上,处理数据。 (也许这会增加时间?)

数据如下:

public class Node
{
    public DateTime Timestamp;
    public float Value;
    public string Name;
}

使用 SqlDataReader 并调用 reader.Read(),然后手动将数据放入上述类的新实例中,将其添加到 List<Node> 也需要 15 秒以上。

代码如下:

List<Node> data = new List<Node>();
while (reader.Read())
{
   Node n = new Node();

   n.Timestamp = (DateTime)reader["Timestamp"];
   n.Value = (float)reader["Value"];
   n.NodeName = (string)reader["NodeName"];

   data.Add(n);
}

我在发布模式下使用 StopWatch 类测量了这一点,并在项目属性中启用了优化。

我知道它必须迭代每条记录,但我希望今天的任何机器都能够在几秒钟内迭代 70 万条记录,但不会更多。

这需要 15 秒以上的原因可能是什么?我期望这会更快吗?

EDIT 单独执行 SqlDataReader.Read() 也需要 15 秒以上。

【问题讨论】:

  • 运行分析器。并检查实际查询需要多长时间。
  • 对您的代码使用 Visual Studio 分析器,看看它在哪里花费时间。
  • 获取Data最快的方法其实就是使用DataReader。所以可能是关于您的数据库查询和/或缺少索引...
  • 查询需要多长时间而不将项目添加到列表中?另外:如果不显示您为迭代阅读器/添加项目而编写的代码,就很难判断。
  • 根据您的说法,我猜——但不能确定——网络速度是瓶颈。您是否尝试过 while(reader.Read()); 来了解需要多长时间才能获得结果,但不采取行动?

标签: c# database performance


【解决方案1】:

我认为问题出在您使用的容器上。 List 正在动态调整大小。请尝试以下步骤:-

run query with a COUNT clause to get the number of records, only select a single column

List<Node> data = new List<Node>(count from above);

run normal query

fill List<> as above

这将防止列表不断调整大小。

或者,要查看这是否是问题所在,请将 List 替换为 LinkedList,因为这没有 List 的大小调整问题。

【讨论】:

    【解决方案2】:

    它应该是数据库和你正在执行代码的机器之间的网络速度。

    【讨论】:

      【解决方案3】:

      在您的循环中还会发生的情况是,您的查询中的值未装箱。尝试GetString, GetFloat, etc methods 可能是值得的,因为您有很多记录。

      List<Node> data = new List<Node>();
      while (reader.Read())
      {
         Node n = new Node();
      
         n.Timestamp = reader.GetDateTime(0); // TODO: Check column numbers
         n.Value = reader.GetFloat(1);
         n.NodeName = reader.GetString(2);
      
         data.Add(n);
      }
      

      在这些方法中不执行任何转换。

      备注

      不执行任何转换;因此,检索到的数据 必须已经是字符串,否则会产生异常。

      【讨论】:

        【解决方案4】:

        我正在阅读很多猜测,这可能是正确的,但它们仍然是猜测。

        如果您在调试器下运行它并手动暂停几次,每次都显示堆栈,您将使用random pausing 方法。 它会准确地告诉您花费时间的原因以及原因 - 无需猜测。

        如果您想使用分析器,您需要一个在挂钟时间进行采样的分析器。 否则,您将不得不在 a) 一个采样器之间进行选择,该采样器为您提供行级包含百分比,而对 IO 时间没有可见性,或者 b) 一个仪器,它只为您提供函数级包含百分比。 没有人告诉你为什么要花时间,只告诉你花了多少时间。 无论您选择什么,请忽略查看自身时间的诱惑,这在任何将所有时间都花在子功能上并且完全忽略 IO 的应用程序中充其量是一种误导。

        【讨论】:

          【解决方案5】:

          如果不是代码问题,那么怀疑它与您的查询计划有关。

          确保在执行查询之前设置了正确的选项。它们在 .NET 和 MSSQL 上的状态相同。

          之前发现会导致性能下降的一个有趣选项是在 SQL 上启用 ARITHABOIRT,在 .NET 上关闭。

          尝试在命令中的查询之前添加 SET ARITHABORT ON。

          参考: Slow performance of SqlDataReader

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-11-30
            • 2018-05-14
            • 1970-01-01
            • 1970-01-01
            • 2011-12-18
            • 1970-01-01
            相关资源
            最近更新 更多