老系统Excel数据导入优化10w数据

  1. 背景:老系统asp.net 2.0项目使用客户反应,某个业务每个月导入数据操作很慢,大致需要15-30分钟才会导入完毕;
  2. 分析:导入慢的原因:

 .数据量过大,且采用的是同步,单个excel sheet 13万+数据;

 .导入前验证,每行某列 验证,频繁和数据库交互

 .使用很老的微软企业库进行批量插入操作,效率低下 ,插入后,又批量进行执行sql修改操作  ;

3 解决方案:

                 修改excel转table 的方案由OpenXMLHelper 转换变为 NPOI;

                  

  1   public class NPOIHelper
  2     {
  3         /// <summary>
  4         /// 将excel导入到datatable
  5         /// </summary>
  6         /// <param name="filePath">excel路径</param>
  7         /// <param name="isColumnName">第一行是否是列名</param>
  8         /// <returns>返回datatable</returns>
  9         public DataTable ExcelToDataTable(string filePath, bool isColumnName)
 10         {
 11             DataTable dataTable = null;
 12             FileStream fs = null;
 13             DataColumn column = null;
 14             DataRow dataRow = null;
 15             IWorkbook workbook = null;
 16             ISheet sheet = null;
 17             IRow row = null;
 18             ICell cell = null;
 19             int startRow = 0;
 20             try
 21             {
 22                 using (fs = File.OpenRead(filePath))
 23                 {
 24                     // 2007版本
 25                     if (filePath.IndexOf(".xlsx") > 0)
 26                         workbook = new XSSFWorkbook(fs);
 27                     // 2003版本
 28                     else if (filePath.IndexOf(".xls") > 0)
 29                         workbook = new HSSFWorkbook(fs);
 30
 31                     if (workbook != null)
 32                     {
 33                         sheet = workbook.GetSheetAt(0);//读取第一个sheet,当然也可以循环读取每个sheet
 34                         dataTable = new DataTable();
 35                         if (sheet != null)
 36                         {
 37                             int rowCount = sheet.LastRowNum;//总行数
 38                             if (rowCount > 0)
 39                             {
 40                                 IRow firstRow = sheet.GetRow(0);//第一行
 41                                 int cellCount = firstRow.LastCellNum;//列数
 42
 43                                 //构建datatable的列
 44                                 if (isColumnName)
 45                                 {
 46                                     startRow = 1;//如果第一行是列名,则从第二行开始读取
 47                                     for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
 48                                     {
 49                                         cell = firstRow.GetCell(i);
 50                                         if (cell != null)
 51                                         {
 52                                             if (cell.StringCellValue != null)
 53                                             {
 54                                                 column = new DataColumn(cell.StringCellValue);
 55                                                 dataTable.Columns.Add(column);
 56                                             }
 57                                         }
 58                                     }
 59                                 }
 60                                 else
 61                                 {
 62                                     for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
 63                                     {
 64                                         column = new DataColumn("column" + (i + 1));
 65                                         dataTable.Columns.Add(column);
 66                                     }
 67                                 }
 68
 69                                 //填充行
 70                                 for (int i = startRow; i <= rowCount; ++i)
 71                                 {
 72                                     row = sheet.GetRow(i);
 73                                     if (row == null) continue;
 74
 75                                     dataRow = dataTable.NewRow();
 76                                     for (int j = row.FirstCellNum; j < cellCount; ++j)
 77                                     {
 78                                         cell = row.GetCell(j);
 79                                         if (cell == null)
 80                                         {
 81                                             dataRow[j] = "";
 82                                         }
 83                                         else
 84                                         {
 85                                             //CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
 86                                             switch (cell.CellType)
 87                                             {
 88                                                 case CellType.BLANK:
 89                                                     dataRow[j] = "";
 90                                                     break;
 91                                                 case CellType.NUMERIC:
 92                                                     short format = cell.CellStyle.DataFormat;
 93                                                     //对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
 94                                                     if (format == 14 || format == 31 || format == 57 || format == 58)
 95                                                         dataRow[j] = cell.DateCellValue;
 96                                                     else
 97                                                         dataRow[j] = cell.NumericCellValue;
 98                                                     break;
 99                                                 case CellType.STRING:
100                                                     dataRow[j] = cell.StringCellValue;
101                                                     break;
102                                             }
103                                         }
104                                     }
105                                     if (dataRow == null)  Logger.Write(string.Format("转换行失败,行数为:{0}", i.ToString()));
106                                     dataTable.Rows.Add(dataRow);
107                                 }
108                             }
109                             else
110                             {
111                                 Logger.Write(string.Format("转换datarow完毕,行数:{0}", rowCount.ToString()));
112                             }
113                         }
114                     }
115                     else
116                     {
117                         Logger.Write("转换workbook 为空");
118                     }
119                 }
120                 return dataTable;
121             }
122             catch (Exception ex)
123             {
124                 Logger.Write(string.Format("转换失败,异常:{0}", ex.ToString()));
125                 if (fs != null)
126                 {
127                     fs.Close();
128                 }
129                 return null;
130             }
131         }
132     }

NPOI

去掉excel的输入验证,由于只是验证数据库是否存在该编码,所以改为由存储过程内连接过滤

                         批量插入修改为使用 SqlBulkCopy,首先创建一张临时表存储需要插入的excel数据(未过滤)

 public int CreateTempTable()
        {
            string createSql = @"
                    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N‘[dbo].[Temp_gdzc]‘) AND type in (N‘U‘))
                    delete FROM [dbo].[Temp_gdzc]
                    IF Not EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N‘[dbo].[Temp_gdzc]‘) AND type in (N‘U‘))
                    BEGIN
                    CREATE TABLE [dbo].[Temp_gdzc](
                        [公司代码] [nvarchar](100) NULL,
                        [资产编号] [nvarchar](100) NULL,
                        [资产次级编号] [nvarchar](100) NULL,
                        [资产描述] [nvarchar](255) NULL,
                        [资产管理序列号] [nvarchar](100) NULL,
                        [资本化日期] [datetime] NULL,
                        [资产原值] [float] NULL,
                        [资产累计折旧] [float] NULL,
                        [资产净值] [float] NULL
                    )
                    end
            ";

            return BusinessRules.Common.SqlHelperBatch.ExecuteNonQuery(createSql, new SqlParameter[] { });

        }

创建临时表

 然后根据临时表 和 要插入的表的数据内关联过滤无效数据,调用存储过程使用 Insert into  select 插入;

 1         //调用存储过程插入明细表
 2                 var parameters = new List<SqlParameter>();
 3                 parameters.Add(new SqlParameter("@MainID", SqlDbType.BigInt, 8) { Value = Mainid });
 4                 parameters.Add(new SqlParameter("@CloseDate", SqlDbType.DateTime) { Value = closeTemp });
 5                 SqlParameter outParameter = new SqlParameter("@ResultCount", SqlDbType.Int, 8);
 6                 outParameter.Direction = ParameterDirection.Output;
 7                 parameters.Add(outParameter);
 8
 9                 var result = BusinessRules.Common.SqlHelperBatch.ExecuteNonQuery(tran, CommandType.Text, "exec P_AssetBalanceQuiry_Insert @MainID, @CloseDate,@ResultCount out", parameters.ToArray());
10                 count = Convert.ToInt32(outParameter.Value == DBNull.Value ? 0 : outParameter.Value);

调用

存储过程如下:

批量插入存储过程

最后批量修改再使用 存储过程 执行关联修改;

CREATE PROCEDURE [dbo].[P_T_UpdateA]
  @MainID int
AS
BEGIN
  UPDATE T1 SET A=C from T2
where A1= B1 AND Main_ID = @MainID
END  

批量修改

需要注意的地方则是:批量插入时,主表ID需要记录,由于是一次操作,只会有一个主表ID,所以会先插入主表,得到主表ID,再批量插入从表;

最终优化操作时间由10分钟 到5-10秒;

                    

原文地址:https://www.cnblogs.com/yanghucheng/p/10272443.html

时间: 2024-10-05 00:25:58

老系统Excel数据导入优化10w数据的相关文章

mysql数据导入到sqlite数据

在做程序时,sqlite数据很方便.用mysql数据导出到sqlite的步骤:(用csv文件过渡) -------------------------------  先导出到csv文件  ------------------------- 1.用navicat软件将mysql数据导出到txt文件. 2.注意选择“包含列标题”(字段名).“栏位定界符”(csv文件使用逗号). 3.把所有的txt文件转换为utf-8编码. 4.写一个rename.bat(ren *.txt *.csv),全部统一改

Oracle11g中数据的倒库和入库操作以及高版本数据导入低版本数据可能引发的问题

1.前言 在10g之前,传统的导出和导入分别使用EXP工具和IMP工具,从10g开始,不仅保留了原有的EXP和IMP工具,还提供了数据泵导出导入工具EXPDP和IMPDP.所以在11G的倒库和入库方式中,我们也有两种方式可以选择:传统模式和数据泵模式. 传统模式又分为:常规导入导出和直接导入导出. 下面以导出数据为例,分别介绍各自导出原理. 1.1简述各导入导出方式的原理 1.1.1常规导出原理 传统路径模式使用SQL SELECT语句抽取表数据.数据从磁盘读入到buffer cache缓冲区中

pl/sql 如何将Excel文件数据导入oracle的数据表?

1.准备导入数据的excel文件 注意:excel列名和数据表列名必须相同,excel文件sheet2和sheet3可以删除 1)excel文件格式 2)数据表格式 2.打开pl/sql ,找到工具---> ODBC导入器 3.选择excel文件,输入用户/密码 4.点击连接,找到磁盘中要导入的文件 5.选择要导入文件的工作表sheet1 6.切换到转入Oracle,选择要导入oracle的那个表 7.点击导入,执行成功,查看结果 原文地址:https://www.cnblogs.com/xie

Excel格式导入导出数据(单语言版本)

Excel格式导入导出数据(单语言版本) 可以使用常用的excel格式导入导出相关数据,包含: 1. 商品分类: 2. 筛选组: 3. 筛选: 4. 商品资料: 5. 商品附加图片资料,(不包含图片本身的上传或抓取): 6. 商品选项: 7. 商品属性: 8. 产品特价数据: 9. 商品折扣数据: 10. 商品奖励积分数据: 特色: 1. 常用excel软件编辑商品数据后导入: 2. 导出的文件名称包含日期和时间,便于备份存档: 3. 由于涉及到服务器的内存,以及数据的多寡,可以将数据按照商品I

oracle数据导入/导出(2)

Oracle数据导入导出imp/exp 功能:Oracle数据导入导出imp/exp就相当与oracle数据还原与备份. 大多情况都可以用Oracle数据导入导出完成数据的备份和还原(不会造成数据的丢失). Oracle有个好处,虽然你的电脑不是服务器,但是你装了oracle客户端,并建立了连接 (通过Net Configuration Assistant添加正确的服务命名,其实你可以想成是客户端与服务器端 修了条路,然后数据就可以被拉过来了) 这样你可以把数据导出到本地,虽然可能服务器离你很远

oracle数据导入/导出

Oracle数据导入导出imp/exp 功能:Oracle数据导入导出imp/exp就相当与oracle数据还原与备份.   大多情况都可以用Oracle数据导入导出完成数据的备份和还原(不会造成数据的丢失).  Oracle有个好处,虽然你的电脑不是服务器,但是你装了oracle客户端,并建立了连接  (通过Net Configuration Assistant添加正确的服务命名,其实你可以想成是客户端与服务器端 修了条路,然后数据就可以被拉过来了)  这样你可以把数据导出到本地,虽然可能服务

Oracle 数据导入导出操作 (转)

Oracle数据导入导出imp/exp 功能:Oracle数据导入导出imp/exp就相当与oracle数据还原与备份. 大多情况都可以用Oracle数据导入导出完成数据的备份和还原(不会造成数据的丢失). Oracle有个好处,虽然你的电脑不是服务器,但是你装了oracle客户端,并建立了连接 (通过Net Configuration Assistant添加正确的服务命名,其实你可以想成是客户端与服务器端 修了条路,然后数据就可以被拉过来了) 这样你可以把数据导出到本地,虽然可能服务器离你很远

hbase0.96数据导入以及Kettle操作hbase问题

版本: cdh5.0.0+hadoop2.3.0+hbase0.96.1.1+Spoon5.0.1 一.HBase数据导入 HBase数据导入使用org.apache.hadoop.hbase.mapreduce.ImportTsv 的两种方式,一种是直接导入,一种是转换为HFile,然后再次导入. 1. HDFS数据为(部分): [[email protected] data]# hadoop fs -ls /input Found 1 items -rwxrwxrwx 1 hdfs supe

关于在sqoop导入数据的时候,数据量变多的解决方案。

今天使用sqoop导入一张表,我去查数据库当中的数据量为650条数据,但是我将数据导入到hive表当中的时候出现了563条数据,这就很奇怪了,我以为是数据错了,然后多导入了几次数据发现还是一样的问题. 然后我去查数据字段ID的值然后发现建了主键的数据怎么可能为空的那.然后我去看数据库当中的数据发现,数据在存入的时候不知道加入了什么鬼东西,导致数据从哪一行截断了,导致多出现了三条数据.下面是有问题的字段. 这里我也不知道数据为啥会是这样,我猜想是在导入数据的时候hive默认行的分割符号是按照\n的