【问题标题】:Loop through DataTable multiple times多次循环遍历DataTable
【发布时间】:2012-02-07 08:22:42
【问题描述】:

在 C# (.NET 3.5) 中,我用我的数据库中的行填充了一个 DataTable。在这个 DataTable 中大约有 100 到 200 个 DataRows。我必须遍历这个 DataTable 来检查数据是否正确,我使用了 27 种检查方法。首先,我尝试将 DataTable 传递给每个方法并循环它。在我的第二次尝试中,我循环了 DataTable 一次并将 DataRow 传递给每个方法。后来我对这两种方法进行了基准测试,第一种方法比第二种方法快?

循环数据表 27 次耗时 13 秒。

循环 DataTable 1 耗时 18 秒。

那么对此有何解释?循环遍历 DataTable 以检查其数据的真正最快方法是什么?

注意:基准测试是在我开始检查方法之前开始的,以排除与数据库的连接速度。

第一种方法:

private void check()
{
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();

    checkStamnr();
    checkVoornaam();
    checkGebDatum();
    ...

    sw.Stop();
    sw.Reset();
}

private void checkStamnr()
{
    foreach (DataRow dr in dtIdentificatieRecords.Rows)
    {
        if (dr["STAMNRVOL"] == null || dr["STAMNRVOL"].GetType() == typeof(DBNull) || dr["STAMNRVOL"].equals(""))
        {
            DatabankFout df = new DatabankFout("Stamnummer is leeg.");
            listDBFouten.Add(df);
        }
    }
}

第二种方法

private void check()
{
    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();

    foreach (DataRow dr in dtIdentificatieRecords.Rows)
    {
        checkStamnr(dr);
        checkVoornaam(dr);
        checkGebDatum(dr);
        ...
    }

    sw.Stop();
    sw.Reset();
}

private void checkStamnr(DataRow dr)
{
    if (dr["STAMNRVOL"] == null || dr["STAMNRVOL"].GetType() == typeof(DBNull) || dr["STAMNRVOL"].equals(""))
    {
        DatabankFout df = new DatabankFout("Stamnummer is leeg.");
        listDBFouten.Add(df);
    }
}

类DatabankFout应要求:

public class DatabankFout
{
    public DatabankFout(string reden, bool rood)
    {
        this.reden = reden;
        this.rood = rood;
    }
    public DatabankFout(string reden) : this(reden, false)
    {
    }

    public string reden { get; set; }
    public bool rood { get; set; }
}

【问题讨论】:

  • 没有看到任何代码就很难帮助...
  • 你的DatabankFout类有多重,listDBFouten是什么?要检查哪种方法更快,您应该删除两者中相同的所有不相关的。循环 100 行绝对不能持续 13/18 秒(除非您使用的是 C64),也许您使用了秒表并且在调试期间忘记了停止/重置(13 毫秒更现实)。而不是传递整个数据表或数据行,你应该只传递需要的东西——存储在数据列中的数据。
  • 能否请您发布有关如何执行计时的代码。
  • DatabankFout 只有一些属性,而 listDBFouten 是一个 List<DatabankFout>,所以没有那么重。

标签: c# loops datatable


【解决方案1】:

我会说,在如此少的项目下一次运行 25% 的运行时间差异并不显着。 对列表中的 10000 个项目至少运行 10 次测试。 如果第一个更快,我会考虑一些事情。

大部分时间可能来自于创建DatabankFout,它可能是一个数据库连接。

【讨论】:

  • DatabankFout 只有属性,与数据库没有任何连接。
  • 那怎么会花这么长时间呢?我们正在谈论几千个属性比较。这可以在不到 1 秒的时间内完成。 listDBFouten.Add 诸如排序之类的东西或者其他慢的东西吗?
  • 您可以在我的开篇文章中看到 DatabankFout。我只是尝试在没有任何检查方法的情况下循环 DataTable 1000 次,它在 7 毫秒内完成。然后我用一种检查方法试了一下,一分钟后还是没有完成。
  • listDBFouten.Add 有什么作用?
  • 正如我之前所说的,listDBFouten 是一个List<DatabankFout>,所以 Add-method 会将DatabankFout 的一个实例添加到列表中......
【解决方案2】:

这对我来说似乎是不可能的。我在我的机器上运行了一个测试。您的第一个多循环方法运行速度比单循环慢得多。

请查看我附上的控制台演示。

class Program
{
    DataTable dtIdentificatieRecords = GetTable();

    String checkTimeSpan, check2TimeSpan;
    static void Main(string[] args)
    {
        Program Test = new Program();
        Test.check();
        Test.check2();

        Console.WriteLine("checkTimeSpan: {0}", Test.checkTimeSpan);

        Console.WriteLine("check2TimeSpan: {0}", Test.check2TimeSpan);

        Console.ReadLine();
    }

    /// <summary>
    /// This example method generates a DataTable.
    /// </summary>
    static DataTable GetTable()
    {
        //
        // Here we create a DataTable with four columns.
        //
        DataTable table = new DataTable();
        table.Columns.Add("STAMNRVOL", typeof(string));
        table.Columns.Add("Drug", typeof(string));
        table.Columns.Add("Patient", typeof(string));
        table.Columns.Add("Date", typeof(DateTime));

        //
        // Here we add five DataRows.
        //
        for (int a = 0; a < 999999; a++)
        {
            table.Rows.Add(a%2==0?a.ToString():"", "Indocin", "David", DateTime.Now);
        }
        return table;
    }

    private void check()
    {
        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();

        checkStamnr();
        checkStamnr();
        checkStamnr();
        checkStamnr();
        checkStamnr();

        stopwatch.Stop();

        checkTimeSpan = stopwatch.Elapsed.TotalSeconds.ToString();

        stopwatch.Reset();
    }

    private void checkStamnr()
    {
        foreach (DataRow dr in dtIdentificatieRecords.Rows)
        {
            if (dr["STAMNRVOL"] == null || dr["STAMNRVOL"].GetType() == typeof(DBNull) || dr["STAMNRVOL"].Equals(""))
            {
                DatabankFout df = new DatabankFout("Stamnummer is leeg.");
            }
        }
    }

    private void check2()
    {
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start();

        foreach (DataRow dr2 in dtIdentificatieRecords.Rows)
        {
            checkStamnr2(dr2);
            checkStamnr2(dr2);
            checkStamnr2(dr2);
            checkStamnr2(dr2);
            checkStamnr2(dr2);

        }

        sw.Stop();

        check2TimeSpan = sw.Elapsed.TotalSeconds.ToString();

        sw.Reset();
    }

    private void checkStamnr2(DataRow dr)
    {
        if (dr["STAMNRVOL"] == null || dr["STAMNRVOL"].GetType() == typeof(DBNull) || dr["STAMNRVOL"].Equals(""))
        {
            DatabankFout df = new DatabankFout("Stamnummer is leeg.");

        }
    }

}

public class DatabankFout
{
    public DatabankFout(string reden, bool rood)
    {
        this.reden = reden;
        this.rood = rood;
    }
    public DatabankFout(string reden)
        : this(reden, false)
    {
    }

    public string reden { get; set; }
    public bool rood { get; set; }
}

【讨论】:

    猜你喜欢
    • 2011-11-01
    • 1970-01-01
    • 2010-10-11
    • 2015-09-22
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 2020-11-10
    • 2019-10-29
    相关资源
    最近更新 更多