代码改变世界

思考探索,如何才能高效访问我的这个DataTable?

  立雪三尺  阅读(2075)  评论(26编辑  收藏  举报

需求

一切都是空的,除了Money,只有需求才是最真的,你懂的。

最近接到个略显棘手的需求,思索再三,想出两种方法,可觉得都不太好,这里与大家讨论一下。

需求如下:

用户需要在现有的某个grid中添加新的一列: Des。现有grid的所有数据DataTable:OraDt都来自一个oracle数据库,而新加的Des值却来自别的四个sqlserver数据库中的某一个。四个SqlServer数据库CHNDB,JPNDB,USDB,CANDB的结构相同,只是数据不同。

根据两个变量:geo和desID可以从前面sql DB中中得到Des的值。geo确定从哪个sql数据库中获取,desID用来得到des的值。 geo和desID就在OraDt中存着,如何才能高效的获取des的值?

geo与sqlserver db对应关系如下:

Geo值 Sqlserver DB
CHN  CHNDB
 JPN  JPNDB
 US  USDB
 CAN  CANDB

解决思路

  1. 从Oracle数据库的某表中查询数据,得到DataTab:OraDt;
  2. OraDt中添加新列: DataColumn("Des", typeof(string));
  3. 遍历OraDt的每一个datarow,取得不同的geo和desID的值;
  4. 根据geo和desID的值确定Sqlserver DB并获得des的值;
  5. 更新OraDt中新列row["Des]的值

解决方案伪代码

  • 这种方法思路比较简单,老老实实遍历OraDt的每一个datarow,取得不同的geo和desID的值,然后从对应的sqlser数据库中获取des的值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//得到oracle datatable,添加row[des],遍历datatable,获取des的值,更新des
      protected void ProcessDataTable()
      {
         //添加新列
          _ds.Tables[0].Columns.Add(new DataColumn("Des", typeof(string)));
          string desID = string.Empty;
          string geo = string.Empty;
 
          //遍历OraDt
          foreach (DataRow row in _ds.Tables[0].Rows)
          {
              if (row["desID"] != DBNull.Value)
                  desID = row["desID"].ToString();
 
              if (!string.IsNullOrEmpty(desID) )
              {
                 //得到geo
                  switch (row["countryId"].ToString())
                      {
                          case Country.US:
                              geo = "US";
                              break;
                          case Country.China:
                              geo = "CHA";
                              break;
                          case Country.Canada:
                              geo = " CAN";
                              break;
                          case Country.Jpan:
                              geo = "JPN";
                              break;
                      }
                  //得到添加des
                  row["Des"]= GetExemptionDes(geo, desID);
                  }
              else row["Des"] = string.Empty;
              }
          }

 GetExemptionDes的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private string GetExemptionDes(string geo, string desid)
{
    string description = string.Empty;
    string query = "select des from taxDes where desid="+desid;
    //确定哪个DB获取数据
    Database DbGEO = DbGEOFactory.CreateDatabase(geo);
    System.Data.Common.DbCommand sqlCmd = DbGEO.GetSqlStringCommand(query);
    //获得des值
    using (IDataReader dr = DbGEO.ExecuteReader(sqlCmd))
    {
        while (dr.Read())
        {
            if (dr["des"] != null)
                description = dr["des"].ToString();
        }
        dr.Close();
    }
    return description;
} 

性能探究:

这种想法思路简单,问题也显而易见,虽然通常情况下OraDt只有十几个row,可极个别时候OraDt的row能达到上千个,这时候,上面的方法要连续访问 Sqlserver DB上千次,显然严重影响了性能。有某有其他的好方法呢?

第二方案,或者其他更好的解决方法?

由于geo最多只有四个,所以我们可以把相同geo下的desID拼接起来,最后一块访问sqlserver db,这样最多只需要访问四次,思路:

      前三步与上面方法一样,

     4.根据geo把desid拼接于一个string变量中

     5.最后一起访问sqlserver db

     6.获得des值,

     7.OraDt更新des

第二方法缺憾:

大量datatable的操作实际上也影响了代码的效率,而且OraDt的数据量通常只有几十行,用这种方法处理普通的OraDt时候显然太过繁琐。

可是现在看来似乎只有这两种方法来解决这个问题了,难道真的就由这么个性能问题存在于我们的代码中么?哪位如果有什么新的解决思路,可以一起分享一下,一起进步。

第一种方法和第二种到底用哪一种好呢?

现将第二方案的详细代码列示如下,由于写的匆忙,还未来的及调试,有什么问题或者哪里可以改进,希望大家多多指正。

可以看到这种方法繁琐操纵OraDt,尤其是在方法UpdateOraDT中,由于某种原因不能使用Linq 来连接datatable,三个foreach 嵌套起来简直不堪入目。处理普通的OraDt时候明显会带来性能问题:

复制代码
protected  void ProcessDataTable()
        {
            _ds.Tables[0].Columns.Add(new DataColumn("ExemptionDes", typeof(string)));

            string desID = string.Empty;
            string geo = string.Empty;

            //建造一个锯齿数组,[0]:geo,[1]: 该geo是否需要被访问,默认0表示不需要,[3]用来拼接desID
            string[][] geoExistArray = new string[4][] { 
                              new string[] { "NA", "0","" },
                              new string[] { "LA", "0","" },
                              new string[] { "EMEA", "0","" },
                              new string[] { "AP", "0","" },
            };
            //遍历datatable
            foreach (DataRow row in _ds.Tables[0].Rows)
            {
                if (row["desID"] != DBNull.Value)
                {
                    xmtn_ID = row["desID"].ToString();
                }

                //如果desID为空,直接将des设置为0
                //不为空,则遍历datatable,取des值
                if (!string.IsNullOrEmpty(desID))
                {
                    switch (row["countryId"].ToString()) {
                        case Country.US:
                            geo = "US";
                            geoExistArray[0][0] = "1";
                            geoExistArray[0][2] = geoExistArray[0][2] + desID+ ",";
                            break;
                        case Country.China:
                            geo = "CHN";
                            geoExistArray[1][0] = "1";
                            geoExistArray[1][2] = geoExistArray[1][2] + desID+ ",";
                            break;
                        case Country.Canada:
                            geo = "CAN";
                            geoExistArray[2][0] = "1";
                            geoExistArray[2][2] = geoExistArray[2][2] + desID+ ",";
                            break;
                        case Country.Jpan:
                            geo = "JPN";
                            geoExistArray[3][0] = "1";
                            geoExistArray[3][2] = geoExistArray[3][2] + desID+ ",";
                            break;
                    }
                }
                else row["Des"] = string.Empty;
            }

            //移除每个拼出的desID字符串中的最后一个逗号
            foreach (var array in geoExistArray)
            {
                if (array[3].Length > 0)
                    array[3].Remove(array[3].Length - 1, 1);
            }
            //获取des值并更新OraDT
            UpdateOraDT(_ds.Tables[0], geoExistArray);
        }
复制代码

UpdateOraDT代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private DataTable UpdateOraDT(DataTable dt, string[][] geoExistArray)
{
    DataTable ExemDesDT;
    foreach (var GeoArrary in geoExistArray)
    {
        //得出一个需要被访问的sql db下的所有des,存于ExemDesDT
        if (GeoArrary[1] == "1")
        {
            ExemDesDT = GetExemptionDesSQL(GeoArrary[0], GeoArrary[2]);
            if (ExemDesDT != null)
                //遍历ExemDesDT,如果ExemDesDT中的id_exemption等于OraDt中的desID ,则获取des
                foreach (DataRow pyrow in ExemDesDT.Rows)
                {
                    foreach (DataRow phxrow in dt.Rows)
                    {
                        if (pyrow["id_exemption"] == phxrow["desID"])
                            phxrow["ExemptionDes"] = pyrow["description"].ToString());
                    }
                }
        }
    }
    return dt;
}

  

GetExemptionDesSQL方法:
复制代码
       private DataTable GetExemptionDesSQL(string geo, string desidList)
        {
            DataTable ExemDesDT = new DataTable();
            string query = " select des from taxDes where desid in (" + desidList+")";
            Database DbGEO = DbGEOFactory.CreateDatabase(geo);
            System.Data.Common.DbCommand sqlCmd = DbPyramid.GetSqlStringCommand(query);
            ExemDesDT = DbGEO.ExecuteDataSet(sqlCmd).Tables[0];
            return ExemDesDT;
        }
复制代码

 

 

 

 

 

 

 

 

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
View Code
点击右上角即可分享
微信分享提示