老系统优化同步导入10w+Excel数据 秒级
- 背景:老系统asp.net 2.0项目使用客户反应,某个业务每个月导入数据操作很慢,大致需要15-30分钟才会导入完毕;
- 分析:导入慢的原因:
.数据量过大,且采用的是同步,单个excel sheet 13万+数据;
.导入前验证,每行某列 验证,频繁和数据库交互
.使用很老的微软企业库进行批量插入操作,效率低下 ,插入后,又批量进行执行sql修改操作 ;
3 解决方案:
修改excel转table 的方案由OpenXMLHelper 转换变为 NPOI;
public class NPOIHelper
{
/// <summary>
/// 将excel导入到datatable
/// </summary>
/// <param name="filePath">excel路径</param>
/// <param name="isColumnName">第一行是否是列名</param>
/// <returns>返回datatable</returns>
public DataTable ExcelToDataTable(string filePath, bool isColumnName)
{
DataTable dataTable = null;
FileStream fs = null;
DataColumn column = null;
DataRow dataRow = null;
IWorkbook workbook = null;
ISheet sheet = null;
IRow row = null;
ICell cell = null;
int startRow = ;
try
{
using (fs = File.OpenRead(filePath))
{
// 2007版本
if (filePath.IndexOf(".xlsx") > )
workbook = new XSSFWorkbook(fs);
// 2003版本
else if (filePath.IndexOf(".xls") > )
workbook = new HSSFWorkbook(fs); if (workbook != null)
{
sheet = workbook.GetSheetAt();//读取第一个sheet,当然也可以循环读取每个sheet
dataTable = new DataTable();
if (sheet != null)
{
int rowCount = sheet.LastRowNum;//总行数
if (rowCount > )
{
IRow firstRow = sheet.GetRow();//第一行
int cellCount = firstRow.LastCellNum;//列数 //构建datatable的列
if (isColumnName)
{
startRow = ;//如果第一行是列名,则从第二行开始读取
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
{
cell = firstRow.GetCell(i);
if (cell != null)
{
if (cell.StringCellValue != null)
{
column = new DataColumn(cell.StringCellValue);
dataTable.Columns.Add(column);
}
}
}
}
else
{
for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
{
column = new DataColumn("column" + (i + ));
dataTable.Columns.Add(column);
}
} //填充行
for (int i = startRow; i <= rowCount; ++i)
{
row = sheet.GetRow(i);
if (row == null) continue; dataRow = dataTable.NewRow();
for (int j = row.FirstCellNum; j < cellCount; ++j)
{
cell = row.GetCell(j);
if (cell == null)
{
dataRow[j] = "";
}
else
{
//CellType(Unknown = -1,Numeric = 0,String = 1,Formula = 2,Blank = 3,Boolean = 4,Error = 5,)
switch (cell.CellType)
{
case CellType.BLANK:
dataRow[j] = "";
break;
case CellType.NUMERIC:
short format = cell.CellStyle.DataFormat;
//对时间格式(2015.12.5、2015/12/5、2015-12-5等)的处理
if (format == || format == || format == || format == )
dataRow[j] = cell.DateCellValue;
else
dataRow[j] = cell.NumericCellValue;
break;
case CellType.STRING:
dataRow[j] = cell.StringCellValue;
break;
}
}
}
if (dataRow == null) Logger.Write(string.Format("转换行失败,行数为:{0}", i.ToString()));
dataTable.Rows.Add(dataRow);
}
}
else
{
Logger.Write(string.Format("转换datarow完毕,行数:{0}", rowCount.ToString()));
}
}
}
else
{
Logger.Write("转换workbook 为空");
}
}
return dataTable;
}
catch (Exception ex)
{
Logger.Write(string.Format("转换失败,异常:{0}", ex.ToString()));
if (fs != null)
{
fs.Close();
}
return null;
}
}
}
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 插入;
//调用存储过程插入明细表
var parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("@MainID", SqlDbType.BigInt, ) { Value = Mainid });
parameters.Add(new SqlParameter("@CloseDate", SqlDbType.DateTime) { Value = closeTemp });
SqlParameter outParameter = new SqlParameter("@ResultCount", SqlDbType.Int, );
outParameter.Direction = ParameterDirection.Output;
parameters.Add(outParameter); var result = BusinessRules.Common.SqlHelperBatch.ExecuteNonQuery(tran, CommandType.Text, "exec P_AssetBalanceQuiry_Insert @MainID, @CloseDate,@ResultCount out", parameters.ToArray());
count = Convert.ToInt32(outParameter.Value == DBNull.Value ? : outParameter.Value);
调用
存储过程如下:
CREATE PROCEDURE [dbo].[P_AssetBalanceQuiry_Insert]
@MainID int ,
@CloseDate datetime,
@ResultCount int=0 output
AS
BEGIN
INSERT INTO T_AssetBalanceQuiry
(
CloseDate,CompanyCode,AssetsCode,AssetsDescribtion,
AssetsNumber,CapitalizationDate,AssetsOldValue,AssetsDepreciation,
AssetsNetWorth,ServiceLife,AssetsType,Main_ID,AssetsCode_sub,Status
)
select @CloseDate,公司代码,CONVERT(decimal(18, 0), 资产编号),资产描述,
管理序列号,资本化日期,资产原值,资产累计折旧,
资产净值, datediff(mm,资本化日期,getdate()),AS_PrimaryNo,@MainID,资产次级编号,null
from dbo.Temp_gdzc
inner join T_Asset on 资产管理序列号 = AS_MSNO;
select @ResultCount = count(1) from T_AssetBalanceQuiry where Main_ID = @MainID;
update T_AssetBalanceMain SET AssetsCount = @ResultCount where ID = @MainID;
END
批量插入存储过程
最后批量修改再使用 存储过程 执行关联修改;
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秒;
老系统优化同步导入10w+Excel数据 秒级的更多相关文章
- Redis实战--使用Jedis实现百万数据秒级插入
echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 当我们 ...
- SQL Server大量数据秒级插入/新增/删除
原文:SQL Server大量数据秒级插入/新增/删除 1.快速保存,该方法有四个参数,第一个参数为数据库连接,第二个参数为需要保存的DataTable,该参数的TableName属性需要设置为数据库 ...
- NPOI导入导出Excel数据
代码: using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; usi ...
- 百度地图Canvas实现十万CAD数据秒级加载
背景 前段时间工作室接到一个与地图相关的项目,我作为项目组成员主要负责地图方面的设计和开发.由于地图部分主要涉及的是前端页面的显示,作为一名Java后端的小白,第一次写了这么多HTML和JavaScr ...
- 关于python导入数据库excel数据时出现102, b"Incorrect syntax near '.15562'.DB-Lib error message 20018, severity 1的问题总结
1.对于在使用python导入sqlsever时,出现102, b"Incorrect syntax near '.15562'.DB-Lib error message 20018, se ...
- 【 转】百度地图Canvas实现十万CAD数据秒级加载
Github上看到: https://github.com/lcosmos/map-canvas 这个实现台风轨迹,这个数据量非常庞大,当时打开时,看到这么多数据加载很快,感到有点震惊,然后自己研究了 ...
- 循序渐进开发WinForm项目(5)--Excel数据的导入导出操作
随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...
- PLSQL导入Excel数据方法
1.把Excel文件另存为(文本文件(制表符分隔)(*.txt)) 2.把新生成的student.txt文件导入到plsql 打开plsql连接到要导入的oracle数据库再打开Tools - ...
- php做EXCEL数据导出导入开发的一些小问题
前两天刚刚做开发CRM系统项目,在做要做EXCEL导出导入功能,因为以前做.NET开发用的是NPOI,但可是没找到PHP版本的,所以就网搜找了个国外的开源PHPEXCEL , 一开始只是做了简单的导入 ...
随机推荐
- XAMPP虚拟主机配置--20150423
你需要一些顶级域名访问方式来访问你本地的项目文件而不是目录方式访问,这时候就需要配置虚拟主机,给你的目录绑定一个域名(本地的话可以通过修改 hosts 文件随便绑定什么域名比如 www.a.com 或 ...
- 【树状数组 思维题】luoguP3616 富金森林公园
树状数组.差分.前缀和.离散化 题目描述 博艾的富金森林公园里有一个长长的富金山脉,山脉是由一块块巨石并列构成的,编号从1到N.每一个巨石有一个海拔高度.而这个山脉又在一个盆地中,盆地里可能会积水,积 ...
- 【Java_基础】java中的多态性
方法的重载.重写和动态链接构成了java的多态性. 1.方法的重载 同一个类中多个同名但形参有所差异的方法,在调用时会根据参数的不同做出选择. 2.方法的重写 子类中重新定义了父类的方法,有关方法重写 ...
- 【Java_基础】空串、空格串、null的区别
1.表示的区别 string str1 = ""; //空串 str1.length() 等于 0 string str2 = " "; / ...
- (1) zabbix进程构成
进程介绍 zabbix_agentd客户端守护进程,此进程收集客户端数据,例如cpu负载.内存.硬盘使用情况等 zabbix_getzabbix工具,单独使用的命令,通常在server或者proxy端 ...
- java发送email一般步骤
java发送email一般步骤 一.引入javamail的jar包: 二.创建一个测试类,实现将要发送的邮件内容写入到计算机本地,查看是否能够将内容写入: public static void mai ...
- Python3 安装pip 提示ModuleNotFoundError: No module named 'distutils.util'
环境ubutun14,python版本是python3.6. 今天在安装Pip 时出现ModuleNotFoundError: No module named 'distutils.util'.操作步 ...
- include/autoconfig.mk
把autoconfig.mk和/include/configs/ $(obj)include/autoconf.mk.dep: $(obj)include/config.h include/commo ...
- linux下防火墙iptables原理及使用
iptables简介 netfilter/iptables(简称为iptables)组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火 ...
- django基础(web框架,http协议,django安装)
学习Django之前我们先来看什么是OSI七层模型: 应用层 表示层 应用层(五层模型中把这三层合成一个应用层) http协议 会话层 传输层 提供端口对 ...