• 数据库批量插入速度实验


    数据库插入速度,哪样最快,特做了一下实验,结果如下:

    可见,不同方式速度相差明显,其中使用SqlBulkCopy最快,在我本机能达到5w条/秒。

    使用SqlBulkCopy的代码如下:

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace BigDataInsertToSqlserver
    {
        /// <summary>
        /// 批量插入数据库
        /// 使用示例:
        /// SqlConnection conn = new SqlConnection(sqlconnstr);
        /// SqlBulkCopyHelper.BulkCopy(conn,usersToInsert.ToList(), 50000, "t_users",300000);
        /// </summary>
        public class SqlBulkCopyHelper
        {
            /// <summary>
            /// 使用 SqlBulkCopy 向 destinationTableName 表插入数据
            /// </summary>
            /// <typeparam name="TModel">必须拥有与目标表所有字段对应属性</typeparam>
            /// <param name="conn"></param>
            /// <param name="modelList">要插入的数据</param>
            /// <param name="batchSize">SqlBulkCopy.BatchSize</param>
            /// <param name="destinationTableName">如果为 null,则使用 TModel 名称作为 destinationTableName</param>
            /// <param name="bulkCopyTimeout">SqlBulkCopy.BulkCopyTimeout</param>
            /// <param name="externalTransaction">要使用的事务</param>
            public static void BulkCopy<TModel>(SqlConnection conn, List<TModel> modelList, int batchSize, string destinationTableName = null, int? bulkCopyTimeout = null, SqlTransaction externalTransaction = null)
            {
                bool shouldCloseConnection = false;
    
                if (string.IsNullOrEmpty(destinationTableName))
                    destinationTableName = typeof(TModel).Name;
    
                DataTable dtToWrite = ToSqlBulkCopyDataTable(modelList, conn, destinationTableName);
    
                SqlBulkCopy sbc = null;
    
                try
                {
                    if (externalTransaction != null)
                        sbc = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, externalTransaction);
                    else
                        sbc = new SqlBulkCopy(conn);
    
                    using (sbc)
                    {
                        sbc.BatchSize = batchSize;
                        sbc.DestinationTableName = destinationTableName;
    
                        if (bulkCopyTimeout != null)
                            sbc.BulkCopyTimeout = bulkCopyTimeout.Value;
    
                        if (conn.State != ConnectionState.Open)
                        {
                            shouldCloseConnection = true;
                            conn.Open();
                        }
    
                        sbc.WriteToServer(dtToWrite);
                    }
                }
                finally
                {
                    if (shouldCloseConnection && conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
    
            public static DataTable ToSqlBulkCopyDataTable<TModel>(List<TModel> modelList, SqlConnection conn, string tableName)
            {
                DataTable dt = new DataTable();
    
                Type modelType = typeof(TModel);
    
                List<SysColumn> columns = GetTableColumns(conn, tableName);
                List<PropertyInfo> mappingProps = new List<PropertyInfo>();
    
                var props = modelType.GetProperties();
                for (int i = 0; i < columns.Count; i++)
                {
                    var column = columns[i];
                    PropertyInfo mappingProp = props.Where(a => a.Name == column.Name).FirstOrDefault();
                    if (mappingProp == null)
                        throw new Exception(string.Format("model 类型 '{0}'未定义与表 '{1}' 列名为 '{2}' 映射的属性", modelType.FullName, tableName, column.Name));
    
                    mappingProps.Add(mappingProp);
                    Type dataType = GetUnderlyingType(mappingProp.PropertyType);
                    if (dataType.IsEnum)
                        dataType = typeof(int);
                    dt.Columns.Add(new DataColumn(column.Name, dataType));
                }
    
                foreach (var model in modelList)
                {
                    DataRow dr = dt.NewRow();
                    for (int i = 0; i < mappingProps.Count; i++)
                    {
                        PropertyInfo prop = mappingProps[i];
                        object value = prop.GetValue(model);
    
                        if (GetUnderlyingType(prop.PropertyType).IsEnum)
                        {
                            if (value != null)
                                value = (int)value;
                        }
    
                        dr[i] = value ?? DBNull.Value;
                    }
    
                    dt.Rows.Add(dr);
                }
    
                return dt;
            }
            static List<SysColumn> GetTableColumns(SqlConnection sourceConn, string tableName)
            {
                string sql = string.Format("select syscolumns.name,colorder from syscolumns inner join sysobjects on syscolumns.id=sysobjects.id where sysobjects.xtype='U' and sysobjects.name='{0}' order by syscolumns.colid asc", tableName);
    
                List<SysColumn> columns = new List<SysColumn>();
                using (SqlConnection conn = (SqlConnection)((ICloneable)sourceConn).Clone())
                {
                    conn.Open();
                    SqlCommand com = conn.CreateCommand();
                    com.CommandText = sql;
                    using (var reader = com.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            SysColumn column = new SysColumn();
                            column.Name = reader.GetString(0);
                            column.ColOrder = reader.GetInt16(1);
    
                            columns.Add(column);
                        }
                    }
                    conn.Close();
                }
    
                return columns;
            }
    
            static Type GetUnderlyingType(Type type)
            {
                Type unType = Nullable.GetUnderlyingType(type); ;
                if (unType == null)
                    unType = type;
    
                return unType;
            }
    
            class SysColumn
            {
                public string Name { get; set; }
                public short ColOrder { get; set; }
            }
    
        }
    }

     例子中用到的表:

    CREATE TABLE [dbo].[T_Users](
        [Id] [uniqueidentifier] NOT NULL,
        [Name] [nvarchar](100) NULL,
        [Gender] [int] NULL,
        [Age] [int] NULL,
        [CityId] [int] NULL,
        [OpTime] [datetime] NULL,
        CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED([Id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
     ) ON [PRIMARY]

    准备要插入的数据,先放到并发集合中ConcurrentBag

     string sqlconnstr = "Data Source=127.0.0.1;Initial Catalog=DBTest;User Id=sa;Password=1";
            ConcurrentBag<User> usersToInsert = new ConcurrentBag<User>();
            int totalCount = 0;
    
            private void InitData()
            {
                usersToInsert = new ConcurrentBag<User>();
                totalCount = int.Parse(txtTotalCount.Text) * 10000;
                for (int i = 0; i < totalCount; i++)
                {
                    usersToInsert.Add(new User() { Id = Guid.NewGuid(), Name = "user"+i, Gender = Gender.Man, Age = 18, CityId = 1, OpTime = DateTime.Now });
                }
            }

    然后调用上方的SqlBulkCopyHelper类进行批量插入数据库

      private void btn2_Click(object sender, EventArgs e)
            {
                Stopwatch sw = new Stopwatch();
                sw.Restart();
                InitData();
                sw.Stop();
                Showlog(string.Format("使用方式三,初始化{0}条数据完成,总耗时{1}毫秒", totalCount, sw.ElapsedMilliseconds));
                sw.Start();
                using (SqlConnection conn = new SqlConnection(sqlconnstr))
                {
                    SqlBulkCopyHelper.BulkCopy(conn,usersToInsert.ToList(), 50000, "t_users",300000);
                }
                sw.Stop();
    
                Showlog(string.Format("使用方式三,插入{0}条数据完成,总耗时{1}毫秒,速度为{2}条/秒", totalCount,sw.ElapsedMilliseconds, Math.Ceiling((double)totalCount*1000/sw.ElapsedMilliseconds)));
            }
  • 相关阅读:
    docker
    iOS开发之抓取花瓣网json数据
    iOS与Android工程项目的简单对比
    Android与iOS的比较
    Jenkins时间和centos时间相差八小时解决方法
    MYSQL中索引里面的基数是什么意思
    使用Java写一个minio的客户端上传下载文件
    Java 使用AOP实现打印日志
    macOS使用brew安装mysql8.x
    MacOS安装homebrew报错:curl: (7) Failed to connect to raw.githubusercontent.com port 443: Connection refused
  • 原文地址:https://www.cnblogs.com/tuyile006/p/13502418.html
Copyright © 2020-2023  润新知