欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# SqlBulkCopy数据批量入库

程序员文章站 2022-07-11 10:40:41
准备条件:20万+数据 界面设计使用的WPF。 没有对比就没有伤害,以下是我两种方式导入数据案例。 运行 结果对比: 首先使用一般sql语句导入,因为时间原因,我就没有等待程序执行完,但是我记录了大约需要多少时间,以及执行了多少时间。导入数据共计:258113条,执行了38秒,已经入库了6971条, ......

准备条件:20万+数据

界面设计使用的WPF。

没有对比就没有伤害,以下是我两种方式导入数据案例。

C# SqlBulkCopy数据批量入库

运行 结果对比:

首先使用一般sql语句导入,因为时间原因,我就没有等待程序执行完,但是我记录了大约需要多少时间,以及执行了多少时间。
导入数据共计:258113条,执行了38秒,已经入库了6971条,大约还需要1429秒。(不去考虑电脑配置,界面数据加载耗时等因素)

C# SqlBulkCopy数据批量入库

接下来我们看看同样的数据量 SqlBulkCopy效果如何:

C# SqlBulkCopy数据批量入库

当我注释代码中使用异步操作,当然,界面会出现假死状态。再来看看运行结果。

C# SqlBulkCopy数据批量入库

 

 C# 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; });

        }
    }