C#操作MsSQL进行大量数据的插入操作

       近期做的是一个对接的同城酒店接口的项目,上面的意思是把同城的酒店数据取到之后拿过来放到自己的服务器上,然后自己家公司的网站用这部分数据的时候查询速度就会块一些,说白了就是搭建一个缓存库。一开始用的单条循环插入的方法,尼玛700多个酒店处理了3分钟左右。我都不敢去交给上面检验。大概算了一下,数据量大概在22w左右,按照700条三分钟算的话(可能但是测试网络不太畅通就有点慢,我取数据是需要时间的,每次最多取100条,一次大概两秒),22w条数据全不干进库里,大概需要900minute,15h。而且这个缓存库最初的想法是每周更新一次数据,更新一次要15个h,想想就脸黑,果断去百度了一下四个字:批量插入。百度大概给出了两个解决方案,第二个解决方案这里就不提了,在.net2.0版本中加入了SqlBlukCopy这个类,专门处理大量数据的。msdn的解释是 使您可以用其他源的数据有效批量加载 SQL Server 表。废话不多说,上代码。
  
  
/// <summary>
/// 批量插入数据
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
public static string InsertHotelListData(List<Hotelhotel> list)
{
string returnStr = string.Empty;
DataTable dt = new DataTable();
var con = new SqlConnection(LocalHotelDb);
try
{
dt = GethotelDataTable(list);
}
catch (Exception ex)
{
LogManager.WriteLog("getdatatable", ex.Message);
}
if (dt != null && dt.Rows.Count > 0)
{
try
{
con.Open();
if (con.State == ConnectionState.Open)
{
using (SqlTransaction ts = con.BeginTransaction())
{
try
{
using (SqlBulkCopy bulk = new SqlBulkCopy(con, SqlBulkCopyOptions.Default, ts))
{
bulk.BatchSize = 1000;
bulk.DestinationTableName = "TC_HotelList";
bulk.NotifyAfter = 100;
//bulk.SqlRowsCopied += new SqlRowsCopiedEventHandler(SqlRowsCopied);
bulk.WriteToServer(dt);
ts.Commit();
//returnStr = "OK";
}
}
catch (Exception ex)
{
LogManager.WriteLog("tsEx", ex.Message);
ts.Rollback();
returnStr = "Error";
}
}
dt.Dispose();
}
}
catch (Exception ex)
{
LogManager.WriteLog("Bulk", ex.Message);
returnStr = "Error";
}
finally
{
con.Close();
con.Dispose();
}
}
return returnStr;
}
其中那个getdatatable是建立你要干进库的数据到数据库表的映射的方法,铁代码:
  
  
/// <summary>
/// 建立datatable映射到数据库中的表
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
private static DataTable GethotelDataTable(List<Hotelhotel> list)
{
DataTable dt = new DataTable();
dt.Columns.Add("hotelId");
dt.Columns.Add("hotelName");
dt.Columns.Add("intro");
dt.Columns.Add("oneWord");
dt.Columns.Add("address");
dt.Columns.Add("nearBy");
dt.Columns.Add("street");
dt.Columns.Add("streetAddr");
dt.Columns.Add("img");
dt.Columns.Add("groupBuy");
dt.Columns.Add("roomType");
dt.Columns.Add("createDate");
dt.Columns.Add("viewCount");
dt.Columns.Add("recmdLevel");
dt.Columns.Add("lowestPrice");
dt.Columns.Add("highestPrice");
dt.Columns.Add("longitude");
dt.Columns.Add("latitude");
dt.Columns.Add("cityId");
dt.Columns.Add("cityName");
dt.Columns.Add("sectionId");
dt.Columns.Add("sectionName");
dt.Columns.Add("bizSectionId");
dt.Columns.Add("bizSectionName");
dt.Columns.Add("chainId");
dt.Columns.Add("chainName");
dt.Columns.Add("starRatedId");
dt.Columns.Add("starRatedName");
dt.Columns.Add("starRatedClass");
dt.Columns.Add("cpList");
dt.Columns.Add("est2List");
dt.Columns.Add("IsFromLocalDb");
for (int i = 0; i < list.Count; i++)
{
DataRow dr = dt.NewRow();
city _city = new city();
section _section = new section();
chain _chain = new chain();
bizSection _bizSection = new bizSection();
starRated _starRated = new starRated();
dr["hotelId"] = Convert.ToInt32(list[i].hotelId);
dr["hotelName"] = list[i].hotelName;
if (string.IsNullOrEmpty(list[i].intro))
{
dr["intro"] = null;
}
else
{
dr["intro"] = list[i].intro;
}
if (string.IsNullOrEmpty(list[i].oneWord))
{
dr["oneWord"] = null;
}
else
{
dr["oneWord"] = list[i].oneWord;
}
 
if (string.IsNullOrEmpty(list[i].address))
{
dr["address"] = null;
}
else
{
dr["address"] = list[i].address;
}
if (string.IsNullOrEmpty(list[i].nearBy))
{
dr["nearBy"] = null;
}
else
{
dr["nearBy"] = list[i].nearBy;
}
if (string.IsNullOrEmpty(list[i].street))
{
dr["street"] = null;
}
else
{
dr["street"] = list[i].street;
}
if (string.IsNullOrEmpty(list[i].streetAddr))
{
dr["streetAddr"] = null;
}
else
{
dr["streetAddr"] = list[i].streetAddr;
}
dr["img"] = list[i].img;
dr["groupBuy"] = Convert.ToInt32(list[i].groupBuy);
dr["roomType"] = list[i].roomType;
dr["createDate"] = list[i].createDate;
dr["viewCount"] = Convert.ToInt32(list[i].viewCount);
dr["recmdLevel"] = Convert.ToInt32(list[i].recmdLevel);
dr["lowestPrice"] = Convert.ToDouble(list[i].lowestPrice);
dr["highestPrice"] = Convert.ToDouble(list[i].highestPrice);
dr["longitude"] = Convert.ToDouble(list[i].longitude);
dr["latitude"] = Convert.ToDouble(list[i].latitude);
_city = list[i].city;
dr["cityId"] = Convert.ToInt32(_city.cityId);
dr["cityName"] = _city.cityName;
if (list[i].section == null)
{
dr["sectionId"] = null;
dr["sectionName"] = null;
}
else
{
_section = list[i].section;
dr["sectionId"] = Convert.ToInt32(_section.sectionId);
dr["sectionName"] = _section.sectionName;
}
if (list[i].chain == null)
{
dr["chainId"] = null;
dr["chainName"] = null;
}
else
{
_chain = list[i].chain;
dr["chainId"] = Convert.ToInt32(_chain.chainId);
dr["chainName"] = _chain.chainName;
}
if (list[i].bizSection == null)
{
dr["bizSectionId"] = null;
dr["bizSectionName"] = null;
}
else
{
_bizSection = list[i].bizSection;
dr["bizSectionId"] = Convert.ToInt32(_bizSection.bizSectionId);
dr["bizSectionName"] = _bizSection.bizSectionName;
}
if (list[i].starRated == null)
{
dr["starRatedId"] = null;
dr["starRatedName"] = null;
dr["starRatedClass"] = null;
}
else
{
_starRated = list[i].starRated;
dr["starRatedId"] = Convert.ToInt32(_starRated.starRatedId);
dr["starRatedName"] = _starRated.starRatedName;
dr["starRatedClass"] = _starRated.starRatedClass;
}
if (list[i].est2List == null)
{
dr["est2List"] = null;
}
else
{
dr["est2List"] = IntegrateEst2List(list[i].est2List);
}
if (list[i].cpList == null)
{
dr["cpList"] = null;
}
else
{
dr["cpList"] = IntegrateCpList(list[i].cpList);
}
dr["IsFromLocalDb"] = 1;
dt.Rows.Add(dr);
}
return dt;
}
先原谅我单个属性的赋值,因为实现最重要么,嘿嘿。在这里要说明一下,如果你的对象的属性跟数据库表中的列名不匹配的话,那么是会报错的。但是这个问题也是可以解决的。 ColumnMappings是SqlBuklCopy类的实例的一个集合属性,把数据载体对象的属性和数据库中的表的列的匹配信息加入到这个集合中,就可以认识了。
   
   
bulk.ColumnMappings.Add("数据载体对象属性名", "数据库表的列名");
ok,然后你就会感觉飞起一样,瞬间大量的数据全部干进去了。
SqlBlukCopy在msdn上的备注很有意思,这里粘过来共勉:

Microsoft SQL Server 提供一个称为 bcp 的流行的命令提示符实用工具,用于将数据从一个表移动到另一个表(表既可以在同一个服务器上,也可以在不同服务器上)。SqlBulkCopy 类允许编写提供类似功能的托管代码解决方案。还有其他将数据加载到 SQL Server 表的方法(例如 INSERT 语句),但相比之下 SqlBulkCopy 提供明显的性能优势。

使用 SqlBulkCopy 类只能向 SQL Server 表写入数据。但是,数据源不限于 SQL Server;可以使用任何数据源,只要数据可加载到 DataTable 实例或可使用 IDataReader 实例读取数据。

一开始不知道Mssql的bcp机制,特意去百度了一下:BCP是SQL Server中负责导入导出数据的一个命令行工具,它是基于DB-Library的,并且能以并行的方式高效地导入导出大批量的数据。BCP可以将数据库的表或视图直接导出,也能通过SELECT FROM语句对表或视图进行过滤后导出。在导入导出数据时,可以使用默认值或是使用一个格式文件将文件中的数据导入到数据库或将数据库中的数据导出到文件中。

其实就是不用C#,改用命令行导入导出数据的玩意。也难怪,SqlBlukCopy就是相当于把BCP代码化了。不过这个玩意确实挺方便啊。还可以把本机的表导入到服务器上,超爽,测试了一下,对服务器的压力不算很大,我测试的时候是百条数据导入一次,能看到cpu的使用率会在每个时间间隔出现一个峰值,就是导入的瞬间。

用这个玩意还需要注意的一点是,他是把数据先放到datatable中,如果你不按时释放datatable的资源,那内存就得扛扛的网上涨。然后哔一声就炸了。。。。希望对各位朋友有帮助。


 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值