C# DataTable数据遍历优化详解

我们在进行开发时,会经常使用DataTable来存储和操作数据,我发现在遍历DataTable并对数据进行删除和添加操作时速度非常慢,查阅相关资料并测试在添加主键后可以使遍历和操作速度提高很多:

测试代码,测试的是我们向取出来数据满足Flag!=1条件的所有数据的后面添加一条数据(因为这条数据的一些字段值是根据前面的几条满足条件[“AccID='” + accID + “' AND Y='” + year + “' AND AbsID <= ” + absID;]数据的值累加得到的)所以需要进行整个DataTable的遍历来计算添加:

public static void Test2()
{
 Stopwatch watch = new Stopwatch();
 using (DbConnection conn = SqlHelper.GetConnection("ConnectionString"))
 {
  using (SqlCommand cmd = new SqlCommand())
  {
   watch.Start();
   cmd.CommandText = string.Format(@"
select ROW_NUMBER() OVER (Order by S.AccID,S.CurrID,S.AbsID,S.Flag)AS RowNum,S.* from Test S
");
   cmd.Connection = conn as SqlConnection;
   cmd.CommandTimeout = 60000;
   conn.Open();
   DataTable table = ExecuteDataTable(cmd);
   watch.Stop();
   Console.WriteLine("从数据库取出数据{0}条", table.Rows.Count);
   Stopwatch watch2 = new Stopwatch();
   watch2.Start();
   DataTable newTable = HandleAccYear(table,true);
   watch2.Stop();
   Console.WriteLine("数据{0},遍历操作时间:毫秒:{1},秒:{2}", newTable.Rows.Count, watch2.ElapsedMilliseconds, watch2.ElapsedMilliseconds / 1000);
  }
  conn.Close();
 }
}

填充数据到DataTable的方法

public static DataTable ExecuteDataTable(SqlCommand cmd)
{
  DataTable table = new DataTable();
  SqlDataAdapter adaper = new SqlDataAdapter(cmd);
  adaper.Fill(table);
  return table;
}
private static DataTable HandleAccYear(DataTable dt, bool isCurrency)
{
  DataTable newdt = dt.Clone();
  //不使用主键
  //dt.PrimaryKey = new DataColumn[] {
  // dt.Columns["AccID"],
  // dt.Columns["Flag"],
  // dt.Columns["AbsID"],
  // dt.Columns["RowNum"],
  //};
  if (dt.Rows.Count > 0)
  {
   object flag = null;
   foreach (DataRow row in dt.Rows)
   {
    flag = row["Flag"];
    if (flag != null && !Helper.AreEqual(flag.ToString(), "1"))
    {
     DataRow newRow = newdt.NewRow();
     DataRow sourceRow = newdt.NewRow();
     sourceRow.ItemArray = row.ItemArray;
     newRow.ItemArray = row.ItemArray;
     string accID = row["AccID"].ToString(),
      year = row["Y"].ToString(),
      absID = row["AbsID"].ToString();
     newRow["Flag"] = "5";
     newRow["SumInfo"] = "测试数据";
     string filter = "AccID='" + accID + "' AND Y='" + year + "' AND AbsID <= " + absID;
     if (!isCurrency)
     {
      filter = "AccID='" + accID + "'AND CurrID='" + row["CurrID"] + "' AND Y='" + year + "' AND AbsID <= " + absID;
     }
     DataRow[] selectRow = dt.Select(filter);
     double debitLC = 0, debitQty = 0, creditLC = 0, creditQty = 0, debitFC = 0, creditFC = 0;
     foreach (DataRow item in selectRow)
     {
      debitLC += ToDouble(item["YearDebitLC"]);
      debitQty += ToDouble(item["YearDebitQty"]);
      creditLC +=ToDouble(item["YearCreditLC"]);
      creditQty += ToDouble(item["YearCreditQty"]);
      if (!isCurrency)
      {
       debitFC += ToDouble(item["YearDebitFC"]);
       creditFC += ToDouble(item["YearCreditFC"]);
      }
     }
     newRow["CurDebitLC"] = debitLC;
     newRow["CurDebitQty"] = debitQty;
     newRow["CurCreditLC"] = creditLC;
     newRow["CurCreditQty"] = creditQty;
     //newRow["CurDebitLC"] = dt.Compute("Sum(YearDebitLC)", filter);
     //newRow["CurDebitQty"] = dt.Compute("Sum(YearDebitQty)", filter);
     //newRow["CurCreditLC"] = dt.Compute("Sum(YearCreditLC)", filter);
     //newRow["CurCreditQty"] = dt.Compute("Sum(YearCreditQty)", filter);
     if (!isCurrency)
     {
      //newRow["CurCreditFC"] = dt.Compute("Sum(YearCreditFC)", filter);
      //newRow["CurDebitFC"] = dt.Compute("Sum(YearDebitFC)", filter);
      newRow["CurCreditFC"] = creditFC;
      newRow["CurDebitFC"] = debitFC;
     }
     newdt.Rows.Add(sourceRow);
     newdt.Rows.Add(newRow);
    }
    else
    {
     DataRow sourceRow = newdt.NewRow();
     sourceRow.ItemArray = row.ItemArray;
     newdt.Rows.Add(sourceRow);
    }
   }
  }
  return newdt;
 }

当不使用主键进行遍历计算插入相应的值时所用时间竟然是这么多:

当我使用同样的方法,同样的数据添加主键(即把HandleAccYear方法中不使用主键下面的注释去掉后).进行遍历计算等操作,得出的结果竟然有这么大的差别:

补充:C# DataTable数据量大,循环处理数据的时候优化速度

相信大家用for循环datatable数据的不会太少,这个在数据量比较小的时候可以接受,但是数据量大的时候却会造成CPU占用过高,甚至把电脑资源耗尽卡死至无限等待,

其实一些循环耗时的操作可以用线程池分块来处理,这样会减轻CPU很多压力,好比食堂打饭,当只有一个窗口的时候势必等待的时间会非常的长,但是多开几个窗口的时候却大大提高效率,

C#中用线程池就可以做到,本来一开始的时候我用的是为每个区块开一个线程,但是有一个问题就是开了那么多的线程没办法结束他们,后来我想到了线程池,

具体代码如下:

int sid = dt.Rows.Count % 100 == 0 ? (dt.Rows.Count / 100) : (dt.Rows.Count / 100 + 1);
    for (int a = 1; a <= sid; a++)
    {
     object aa=a.ToString() + "," + sid.ToString();
     ThreadPool.QueueUserWorkItem(todo
      , aa);
    }
 public void todo(object aa)
 {
  string sql = "";
  int startindex = Convert.ToInt32(aa.ToString().Split(',')[0]);
  int limitstep = Convert.ToInt32(aa.ToString().Split(',')[1]);
  for (int i = (startindex > 1 ? ((startindex - 1) * 100) : 0); i < (startindex == limitstep ? (dt.Rows.Count) : startindex*100); i++)
  {
   //todo数据操作
  }
  Thread.Sleep(2000);
 }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • C# 遍历datatable字段名和value的案例

    遍历datatable的方法: DataTable dt = dataSet.Tables[0]; foreach (DataColumn col in dt .Columns) { string name=col.ColumnName;//获取到DataColumn列对象的列名 dt.columns[行数][col.ColumnName].tostring() } foreach (System.Data.DataColumn k in dataTable.Columns) { columnN

  • C#过滤DataTable中空数据和重复数据的示例代码

    C#过滤DataTable中的空数据和重复数据 string sql = "select name,age from user"; DataTable data = DB.ExecuteDataTable(string.Format(sql)); //得到DataTable // ------------start 去重------------------- string[] distinctcols = new string[(data.Columns.Count)]; foreac

  • C# DataTable与Model互转的示例代码

    /// <summary> /// 实体转换辅助类 /// </summary> public class ModelConvertHelper<T> where T : new() { /// <summary> /// List泛型转换DataTable. /// </summary> public DataTable ListToDataTable<T>(List<T> items) { var tb = new D

  • C# Datatable的几种用法小结

    在C#中,从数据库中读取出来的数据一般都会存储在datatable中.datatable其实也是一张表,就像是从数据库中将检索出来的结果copy到datatable中一样.datatable的内部数据结构就是这样的 一个二维表. 下面介绍一下datatable中的几种用法. 添加引用 //引用命名空间 using System.Data; 创建表 //创建一个空表 DataTable dt = new DataTable(); //创建一个名为"new-tabel"的空表: DataT

  • C#中的DataTable查询实战教程

    DataTable查询 工作中遇到了需要进行DataTable进行查询的需求,简单研究了一下,最终使用一下方案实现,简单记录一下便于以后使用. DataTable dt = dataBox.GetDataForDataTable();//获取DataTable所有数据,准备进行查询 DataRow[] dtRow = dt.Select("调剂日期='"+MediumCode.Text.Trim()+"'");//根据查询条件,筛选出所有满足条件的列 DataTab

  • C# DataTable数据遍历优化详解

    我们在进行开发时,会经常使用DataTable来存储和操作数据,我发现在遍历DataTable并对数据进行删除和添加操作时速度非常慢,查阅相关资料并测试在添加主键后可以使遍历和操作速度提高很多: 测试代码,测试的是我们向取出来数据满足Flag!=1条件的所有数据的后面添加一条数据(因为这条数据的一些字段值是根据前面的几条满足条件["AccID='" + accID + "' AND Y='" + year + "' AND AbsID <= &quo

  • MySQL Limit性能优化及分页数据性能优化详解

    MySQL Limit可以分段查询数据库数据,主要应用在分页上.虽然现在写的网站数据都是千条级别,一些小的的优化起的作用不大,但是开发就要做到极致,追求完美性能.下面记录一些limit性能优化方法. Limit语法: SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset LIMIT子句可以被用于强制 SELECT 语句返回指定的记录数.LIMIT接受一个或两个数字参数.参数必须是一个整数常量. 如果给定两个参数,第一个参数指定

  • java 较大数据量取差集,list.removeAll性能优化详解

    今天在优化项目中的考勤同步功能时遇到将考勤机中的数据同步到数据库, 两边都是几万条数据的样子,老代码的做法差不多半个小时,优化后我本机差不多40秒,服务器速度会更加理想. 两个数据集取差集首先想到的方法便是List.removeAll方法,但是实验发现jdk自带的List.removeAll效率很低 List.removeAll效率低原因: List.removeAll效率低和list集合本身的特点有关 : List底层数据结构是数组,查询快,增删慢 1.List.contains()效率没有h

  • Android Gradle同步优化详解

    目录 动态修改gradle配置 hook agp ProjectsServices 方法签名检查是否存在support包 年初开始我们就开始了关于Gradle Sync阶段的优化.之前和大家都简单的介绍过工程相关的背景情况了,我们大概有400+的Module,然后一次的同步时间就非常的慢,我们迫切的需要对这个问题进行优化.大部分工作都是和团队内的同学一起完成的,我也只出了一点点力而已. 这次写文章真的很倒霉,之前忘了保存导致要重新开始写了.如果不是白嫖了掘金的端午礼盒,拿人手短啊,我已经打算鸽了

  • Android性能优化之弱网优化详解

    目录 弱网优化 1.Serializable原理 1.1 分析过程 1.2 Serializable接口 1.3 ObjectOutputStream 1.4 序列化后二进制文件的一点解读 1.5 常见的集合类的序列化问题 1.5.1 HashMap 1.5.2 ArrayList 2.Parcelable 2.1 Parcel的简介 2.2 Parcelable的三大过程介绍(序列化.反序列化.描述) 2.2.1 描述 2.2.2 序列化 2.2.3 反序列化 2.3 Parcelable的实

  • AJAX实现JSON与XML数据交换方法详解

    目录 1.JS中如何创建和访问JSON对象 2.基于JSON的数据交换 3.基于XML的数据交换 1.JS中如何创建和访问JSON对象 (1)在javascript语言中怎么创建一个json对象,语法是什么? "属性名" : 属性值,"属性名" : 属性值.........的格式! 注意:属性值的数据类型随意:可能是数字,可能是布尔类型,可能是字符串,可能是数组,也可能是一个json对象..... <!DOCTYPE html> <html lan

  • Python实现随机森林RF模型超参数的优化详解

    目录 1 代码分段讲解 1.1 数据与模型准备 1.2 超参数范围给定 1.3 超参数随机匹配择优 1.4 超参数遍历匹配择优 1.5 模型运行与精度评定 2 完整代码 本文介绍基于Python的随机森林(Random Forest,RF)回归代码,以及模型超参数(包括决策树个数与最大深度.最小分离样本数.最小叶子节点样本数.最大分离特征数等)自动优化的代码. 本文是在上一篇文章Python实现随机森林RF并对比自变量的重要性的基础上完成的,因此本次仅对随机森林模型超参数自动择优部分的代码加以详

  • C#中DataTable 转实体实例详解

    因为Linq的查询功能很强大,所以从数据库中拿到的数据为了处理方便,我都会转换成实体集合List<T>. 开始用的是硬编码的方式,好理解,但通用性极低,下面是控件台中的代码: using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Demo1 { class Pr

  • 基于Python中单例模式的几种实现方式及优化详解

    单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. 比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息.如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪

  • js构建二叉树进行数值数组的去重与优化详解

    前言 本文主要介绍了关于js构建二叉树进行数值数组的去重与优化的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 常见两层循环实现数组去重 let arr = [11, 12, 13, 9, 8, 7, 0, 1, 2, 2, 5, 7, 11, 11, 7, 6, 4, 5, 2, 2] let newArr = [] for (let i = 0; i < arr.length; i++) { let unique = true for (let j = 0; j

随机推荐