zoukankan      html  css  js  c++  java
  • 比较两个DataTable数据(结构相同)——5万条数据仅需几秒

    最近项目上有一个功能,要求是实时采集和更新可售商品记录。可售商品信息来源于另外一套销售系统的接口。
    通常可售商品记录在8万条左右,采集的数据不提供主键,按照一系列的字段内容识别是否相同,好多字段为null值。(所以无法进行主键比较)
    采集和保存的业务规则是:
    从采集的数据中对照数据库中,采集的数据中存在而库中不存在的商品,属于新增加的商品记录,需要增加到库中。
    而库中存在但采集的数据中不存在的,则属于已经销售的商品,需要从库中删除。
    为此查阅了很多xdjm的代码,给出了若干解决方法。
    可惜在数据量很小的情况还行,当使用实际数据进行时,对照时间已经不能忍受。
    于是只能苦思冥想,自行写出了一个方法,贴出来供大家研究,如果发现有bug,请及时告知。

    2012-5-10 PS

    很感谢一直以来关注本帖的朋友们,原来的代码不是很完善,后来修改了也一直不曾更新,换了个思路重构了代码,如果发现有误请留言。

    新代码解决了现有的几个bug,也接受了一些朋友的建议,未经测试,请检查后使用。 

    View Code 
      1         /// <summary>
      2         /// 比较两个DataTable数据(结构相同,字段名不同)
      3         /// </summary>
      4         /// <param name="dtDest">来自数据库的DataTable</param>
      5         /// <param name="dtSrc">来自文件的DataTable</param>
      6         /// <param name="dtRetAdd">新增数据(dt2中的数据)</param>
      7         /// <param name="dtRetDel">删除的数据(dt2中的数据)</param>
      8         /// <param name="srcKeyFields">源关键字段名</param>
      9         /// <param name="destKeyFields">目标关键字段名,与源关键字段名对应</param>
     10         public static void CompareDt(DataTable dtSrc, DataTable dtDest, out DataTable dtRetAdd, out DataTable dtRetDel, string srcKeyFields, string destKeyFields)
     11         {
     12             //源记录集与目标记录集有一个为null则退出
     13             if (dtSrc == null || dtDest == null)
     14             {
     15                 dtRetDel = null;
     16                 dtRetAdd = null;
     17                 return;
     18             }
     19             //定义返回记录表
     20             dtRetDel = dtSrc.Clone();
     21             dtRetAdd = dtRetDel.Clone();
     22             //参照列为空则退出
     23             if (string.IsNullOrEmpty(srcKeyFields) || string.IsNullOrEmpty(destKeyFields))
     24                 return;
     25             //获得参照列列表
     26             string[] srcFields = srcKeyFields.Split(',');//列名数组
     27             string[] destFields = destKeyFields.Split(',');//列名数组
     28             //参照列数目不一致则退出
     29             if (srcFields.Length != destFields.Length)
     30                 return;
     31             //按参照列排序源表和目标表
     32             DataRow[] drSrc = dtSrc.Select("", srcKeyFields);
     33             DataRow[] drDest = dtDest.Select("", destKeyFields);
     34             //定义源表和目标表长度
     35             int iSrcCount = drSrc.Length;
     36             int iDestCount = drDest.Length;
     37             //源表为空则目标表全部加入删除队列并返回
     38             if (iSrcCount == 0)
     39             {
     40                 foreach (DataRow row in drDest)
     41                 {
     42                     dtRetDel.Rows.Add(row.ItemArray);
     43                 }
     44                 return;
     45             }
     46             //目标表为空则源表全部加入新增队列并返回
     47             if (iDestCount == 0)
     48             {
     49                 foreach (DataRow row in drSrc)
     50                 {
     51                     dtRetAdd.Rows.Add(row.ItemArray);
     52                 }
     53                 return;
     54             }
     55             //定义源表和目标表指针
     56             int iSrc = 0;
     57             int iDest = 0;
     58             //开始循环比对
     59             while (iSrc < iSrcCount && iDest < iDestCount)
     60             {
     61                 //定义列比对结果
     62                 int result = 0;
     63                 object oSrc;
     64                 object oDest;
     65                 //循环比对列值
     66                 for (int colIndex = 0; colIndex < srcFields.Length; colIndex++)
     67                 {
     68                     //获得列值
     69                     oSrc = drSrc[iSrc][srcFields[colIndex]];
     70                     oDest = drDest[iDest][destFields[colIndex]];
     71                     //比较列值,不相等则退出循环
     72                     if (oSrc == DBNull.Value)
     73                     {
     74                         result = oDest == DBNull.Value ? 0 : -1;
     75                     }
     76                     else
     77                     {
     78                         result = oDest == DBNull.Value ? 1 : string.Compare(oSrc.ToString(), oDest.ToString(), false);
     79                     }
     80                     if (result != 0)
     81                         break;
     82                 }
     83                 //检查行比较结果
     84                 switch (result)
     85                 {
     86                     ////源表小则将源表本行加入新增队列,同时移动源表指针
     87                     case -1:
     88                         dtRetAdd.Rows.Add(drSrc[iSrc].ItemArray);
     89                         iSrc++;
     90                         break;
     91                     ////相同两表同时移动指针
     92                     case 0:
     93                         iSrc++;
     94                         iDest++;
     95                         break;
     96                     ////目标表小则将目标表本行加入删除队列,同时移动目标表指针
     97                     case 1:
     98                         dtRetDel.Rows.Add(drDest[iDest].ItemArray);
     99                         iDest++;
    100                         break;
    101                     default:
    102                         break;
    103                 }
    104             }
    105             //源表到达最后一条,目标表未到达,则目标表剩余行全部加入删除队列
    106             if (iDest < iDestCount)
    107             {
    108                 for (int index = iDest; index < iDestCount; index++)
    109                 {
    110                     dtRetDel.Rows.Add(drDest[index].ItemArray);
    111                 }
    112             }
    113             //目标表到达最后一条,源表未到达,则源表剩余行全部加入新增队列
    114             else if (iSrc < iSrcCount)
    115             {
    116                 for (int index = iSrc; index < iSrcCount; index++)
    117                 {
    118                     dtRetAdd.Rows.Add(drSrc[index].ItemArray);
    119                 }
    120             }
    121
  • 相关阅读:
    docker~save与load的使用
    docker~从Dockerfile到Container的过程(终于算是OK了)
    docker~使用阿里加速器
    Draw2d中的布局管理器Layout比较
    利用glibc中锁结构的信息解决死锁问题
    android 利用重力感应监听 来电时翻转手机后静音。
    hdu 1754 I Hate It
    九度笔记之 1209最小邮票数
    java zip工具类
    基于XMPP实现的Openfire的配置安装+Android客户端的实现
  • 原文地址:https://www.cnblogs.com/cpmu/p/1721298.html
Copyright © 2011-2022 走看看