C# SqlBulkCopy数据批量入库
准备条件:20万+数据
界面设计使用的WPF。
没有对比就没有伤害,以下是我两种方式导入数据案例。
运行 结果对比:
首先使用一般sql语句导入,因为时间原因,我就没有等待程序执行完,但是我记录了大约需要多少时间,以及执行了多少时间。
导入数据共计:258113条,执行了38秒,已经入库了6971条,大约还需要1429秒。(不去考虑电脑配置,界面数据加载耗时等因素)
接下来我们看看同样的数据量 SqlBulkCopy效果如何:
当我注释代码中使用异步操作,当然,界面会出现假死状态。再来看看运行结果。
解析数据时间明显减少。
以下是这个测试工具的全部代码:
/// <summary> /// BatchImportForm.xaml 的交互逻辑 /// </summary> public partial class BatchImportForm : Window { private static readonly string ConnStr = ConfigurationManager.ConnectionStrings["myconnStr"].ConnectionString; public BatchImportForm() { InitializeComponent(); } private void BtnQueryImport_Click(object sender, RoutedEventArgs e) { var filePath = GetFilePath(); if (!string.IsNullOrEmpty(filePath)) { // 防止界面假死状态 Task task = Task.Factory.StartNew(() => { SqlWork(filePath); }); } } private string GetFilePath() { // 读取文本文件 OpenFileDialog ofd = new OpenFileDialog(); ofd.InitialDirectory = System.Environment.CurrentDirectory+ "\\Resources\\Txt"; // @"C:\Users\WenDaoJun\Documents\Visual Studio 2015\Projects\JWell\JWell.Cloud.UI\Resources\Txt"; ofd.Title = "读取文件"; ofd.FileName = ""; ofd.RestoreDirectory = true; ofd.Filter = "所有文件(*.*)|*.*|文本文件(*.txt)|*.txt"; ofd.ValidateNames = true; ofd.CheckFileExists = true; ofd.CheckPathExists = true; string strName = string.Empty; if (ofd.ShowDialog() == true) { strName = ofd.FileName; } if (strName == "") { MessageBox.Show("没有选择文件!"); return null; } return strName; } private void BtnQueryImportTwo_Click(object sender, RoutedEventArgs e) { string filePath = GetFilePath(); //if (!string.IsNullOrEmpty(filePath)) //{ // Task task = Task.Factory.StartNew(() => // { // SqlBulkWord(filePath); // }); //} SqlBulkWord(filePath); } /// <summary> /// 第一种方法 /// </summary> /// <param name="fuillPath"></param> private void SqlWork(string fuillPath) { var lines = File.ReadAllLines(fuillPath, Encoding.Default); // 异步给控件赋值 this.Dispatcher.Invoke(() => { this.JingDuOn.Maximum = lines.Length; }); this.Dispatcher.Invoke(() => { this.LblRuKuOne.Content = lines.Length; }); using (SqlConnection conn = new SqlConnection(ConnStr)) { conn.Open(); var t1 = DateTime.Now; for (int i = 0; i < lines.Length; i++) { // 拼接数据 // 解析文本文件 "\"号段\"\t\"所属地区\"\t\"号码类型\"\t\"区号\"" var strs = lines[i].Split('\t'); var telNumber = strs[0].Trim('"'); var telArea = strs[1].Trim('"'); var telType = strs[2].Trim('"'); var telAreaCode = strs[3].Trim('"'); // 入库 using (SqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = @"insert into TelNum(TelNumber,TelType,TelArea,TelAreaCode) values(@TelNumber,@TelType,@TelArea,@TelAreaCode)"; cmd.Parameters.Add(new SqlParameter("@TelNumber", telNumber)); cmd.Parameters.Add(new SqlParameter("@TelType", telArea)); cmd.Parameters.Add(new SqlParameter("@TelArea", telType)); cmd.Parameters.Add(new SqlParameter("@TelAreaCode", telAreaCode)); cmd.ExecuteNonQuery(); //异步委托 this.JingDuOn.Dispatcher.Invoke(() => { this.JingDuOn.Value += 1; }); this.LblJinDuOne.Dispatcher.Invoke(() => { this.LblJinDuOne.Content = i; }); } var t2 = DateTime.Now; var tsp = t2 - t1; // 异步给控件赋值 this.LblHaoShiOne.Dispatcher.Invoke(() => { this.LblHaoShiOne.Content = tsp.TotalSeconds; }); this.LblZongHaoShiOne.Dispatcher.Invoke(() => { this.LblZongHaoShiOne.Content = $"倒计时{(tsp.TotalSeconds * lines.Length / (i + 1))}秒完成。"; }); } } } /// <summary> /// 第二种方法 /// </summary> /// <param name="filePath"></param> private void SqlBulkWord(string filePath) { var lines = File.ReadAllLines(filePath, Encoding.Default); this.Dispatcher.Invoke(() => { this.JingDuTwo.Maximum = lines.Length; }); this.Dispatcher.Invoke(() => { this.LblRuKuTwo.Content = lines.Length; }); var t1 = DateTime.Now; // 创建入库需要的数据源 DataTable DataTable dt = new DataTable(); dt.Columns.Add(new DataColumn("TelNumber", typeof(string))); dt.Columns.Add(new DataColumn("TelType", typeof(string))); dt.Columns.Add(new DataColumn("TelArea", typeof(string))); dt.Columns.Add(new DataColumn("TelAreaCode", typeof(string))); for (int i = 0; i < lines.Length; i++) { var row = dt.NewRow(); // 拼接数据 // 解析文本文件 "\"号段\"\t\"所属地区\"\t\"号码类型\"\t\"区号\"" var strs = lines[i].Split('\t'); row["TelNumber"] = strs[0].Trim('"'); row["TelType"] = strs[1].Trim('"'); row["TelArea"] = strs[2].Trim('"'); row["TelAreaCode"] = strs[3].Trim('"'); dt.Rows.Add(row); this.JingDuTwo.Dispatcher.Invoke(() => { this.JingDuTwo.Value += 1; }); this.LblJinDuTwo.Dispatcher.Invoke(() => { this.LblJinDuTwo.Content = i; }); } var t2 = DateTime.Now; var tsp = t2 - t1; this.LblHaoShiTwo.Dispatcher.Invoke(() => { this.LblHaoShiTwo.Content = tsp.TotalSeconds; }); // 入库计时 var sw = new Stopwatch(); sw.Start(); using (SqlBulkCopy sbk = new SqlBulkCopy(ConnStr)) { //表名 sbk.DestinationTableName = "TelNum"; //DataTable中的列名和数据库中列名对应 sbk.ColumnMappings.Add("TelNumber", "TelNumber"); sbk.ColumnMappings.Add("TelType", "TelType"); sbk.ColumnMappings.Add("TelArea", "TelArea"); sbk.ColumnMappings.Add("TelAreaCode", "TelAreaCode"); sbk.WriteToServer(dt); } sw.Stop(); this.LblZongHaoShiTwo.Dispatcher.Invoke(() => { this.LblZongHaoShiTwo.Content=sw.Elapsed.TotalSeconds; }); } }