• 使用SQLBULKCOPY提高导入数据的性能


    向SQL Server中导入大量数量可以用bulk insert,但是必须要求插入的文件在数据库机器上或者一个数据库可以访问的共享文件夹中(我不知道怎么设置共享文件夹,以使得SQL Server能访问到)

    SqlBulkCopy 是.net中的一个类,提供了导入大量数据的功能。

    基本用法如下:

    using (SqlBulkCopy bc = new SqlBulkCopy(sqlConn, SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.UseInternalTransaction, null))
    {
         bc.BulkCopyTimeout = 10 * 60;
         bc.BatchSize = 10000;
         bc.DestinationTableName = "dbo.Destination";
         bc.WriteToServer(reader); //reader 是一个继承自IDataReader的类的实例
    }

     

    自己可以写代码来实现继承自IDataReader的类。有n多成员要实现。。。

    比如FieldCount, Read(), GetValue(int i), Close()等

    下面是一个读文件的例子:

     

    View Code
    //返回记录的列数
            public int FieldCount  
            {
                 get { return 3; }
            }
    
            //读记录,此方法会被自动调用
            public bool Read()
            {
                if (_Reader == null)
                    _Reader = new StreamReader(_FilePath);
    
                string line = _Reader.ReadLine();
                
                if (line != null)
                {
                    _CurrentQueryItem = GetRawData(line);
                    _Count++;
    
                    while (_CurrentQueryItem == null)//如果读出的是不满足条件的记录,则读下一条记录
                    {
                        Read();
                    }
                    return true;
                }            
                return false;
            }
    
            //返回一条记录中第i 列(项)的值,此方法会被自动调用
        //SqlBulkCopy内部应该有一个循环,从0到FieldCount -1 ,再调用GetValue(int i)这个方法。我猜的。。。
            public object GetValue(int i)
            {
                if (_CurrentQueryItem == null)
                    return null;
    
                switch (i)
                {
                    //如果数据库中表的第一列是自增字段,则会忽略第一列,也就是说此方法被调用时,i只会从1开始,所以不需要case 0的情况。估计.net内部去取目的表的schema,自动判断哪些列是需要从外部导入的。有空再研究这个问题
                    case 0:
                        return _CurrentQueryItem.Item1;
                    case 1:
                        return _CurrentQueryItem.Item2;
                    case 2:
                        return _CurrentQueryItem.Item3;
                    default:
                        throw new IndexOutOfRangeException();
                }
            }
    
            //释放资源
            public void Close()
            {
                Dispose();
            }
    
            public void Dispose()
            {
                if (_Reader != null)
                    _Reader.Close();
            }

     

    有一些其他属性其方法需要自己实现,当然有的不实现也没关系。似乎重要的就以上几个方法了。
    对照SqlDataRead,自己可以猜想出会用到哪些方法。

    经过实验,一个文件如果一行一行插入到数据库里,需要大约2分钟,如果用SqlBulkCopy 10秒左右就完成了。而且可以自己实现类来指定处理什么数据,也不用把文件放在数据库机器上了。不错。

    忘说了,SqlBulkCopy里用到的connction对象只能是SqlConnection。SqlBulkCopy.WriteToServer (DataRow]) 和SqlBulkCopy.WriteToServer (DataTable) 都是可以的。

  • 相关阅读:
    Golang 用go-sql-driver 调用MySQL存储过程时的问题排查
    mysqlbinlog 查看binlog时报错unknown variable 'default-character-set=utf8'
    HBase Go客户端Row构造注意事项
    MySQL JOIN操作报错问题小解
    MySQL主从同步的一个小问题解决
    PHP 多个mysql连接的问题
    记一起动态库加载错误问题排查过程
    DNS缓存
    C输出大于127的ACSII字符
    Mint17 一些安装备忘
  • 原文地址:https://www.cnblogs.com/weixing/p/2755166.html
Copyright © 2020-2023  润新知