最近在写一个数据导入的程序,从excel中读取数据,再插入到db中,如果采用insert语句或procedure逐行插入数据,每次都需要sqlconnection.open(),sqlconnection.close(),我想是不是会产生很大的开销。而DataSet自身带有update的方法,听说可以打批量的插入数据,而且性能很高。所以我写了个程序测试一下写入的速度(代码如下),但是另我惊讶的是测试结果如下:
生产数据条数:10000
insert插入10000条记录时间:00:00:04.8593750
dataset.update插入10000条记录时间:00:00:05.5781250
为什么会这样呢,不是说insert的系统开销大于dataset.update()的吗?请各位指点。
另外,还有什么更好,效率更高的数据批量插入DB的方法。谢谢。
        private void testinputdate()
        {
            DateTime startdate = DateTime.Now; 
            SqlConnection sqlconnection = new SqlConnection(connectionString);
            SqlDataAdapter sqldataadapter = new SqlDataAdapter("select * from Table_1 where 1=2", sqlconnection);
            DataSet dataset = new DataSet();
            sqldataadapter.Fill(dataset, "Table_1");
            Console.WriteLine("执行查询时间:{0}",(DateTime.Now - startdate).ToString());            startdate=DateTime.Now;
            DataTable datatable = dataset.Tables[0];
            for (int i = 0; i < 100000; i++)
            {
                DataRow datarow = datatable.NewRow();
                datarow["CompanyName"] = "companyname"+string.Format("{0:0000}",i);
                datarow["CompanyCode"] = "companycode" + string.Format("{0:0000}", i);
                datarow["Address"] = "address" + string.Format("{0:0000}", i);
                datarow["Owner"] = "owner" + string.Format("{0:0000}", i);
                datarow["Memo"] = "memo" + string.Format("{0:0000}", i);                datatable.Rows.Add(datarow); 
            }
            Console.WriteLine("生成数据时间:{0}", (DateTime.Now - startdate).ToString());
            Console.WriteLine("生产数据条数:{0}", datatable.Rows.Count);            //使用insert
            startdate = DateTime.Now;
            foreach (DataRow datarow in datatable.Rows)
            {
                string sql = "INSERT INTO [Table_1]([CompanyName],[CompanyCode],[Address],[Owner],[Memo])" +
                           "VALUES('" + datarow["CompanyName"].ToString() + "'" +
                           ",'" + datarow["CompanyCode"].ToString() + "'" +
                           ",'" + datarow["Address"].ToString() + "'" +
                           ",'" + datarow["Owner"].ToString() + "'" +
                           ",'" + datarow["Memo"].ToString() + "')";
                using (SqlConnection sqlconn = new SqlConnection(connectionString))
                {
                    sqlconn.Open();
                    SqlCommand sqlcommand = new SqlCommand(sql, sqlconn);
                    sqlcommand.ExecuteNonQuery();
                    sqlconn.Close();
                }
            }
            Console.WriteLine("插入{0}条记录时间:{1}", datatable.Rows.Count, DateTime.Now - startdate);
                        
            
            SqlCommand insertcommand = new SqlCommand("INSERT INTO [Table_1]([CompanyName],[CompanyCode],[Address],[Owner],[Memo])" +
                                                "VALUES(@CompanyName, @CompanyCode,@Address,@Owner,@Memo)",new SqlConnection(connectionString));
            insertcommand.Parameters.Add("@CompanyName", SqlDbType.NChar, 50, "CompanyName");
            insertcommand.Parameters.Add("@CompanyCode", SqlDbType.NChar, 25, "CompanyCode");
            insertcommand.Parameters.Add("@Address", SqlDbType.NChar, 255, "Address");
            insertcommand.Parameters.Add("@Owner", SqlDbType.NChar, 25, "Owner");
            insertcommand.Parameters.Add("@Memo", SqlDbType.NChar, 255, "Memo");
            sqldataadapter.InsertCommand = insertcommand;            //使用dataadapter.update
            startdate = DateTime.Now;
            sqldataadapter.Update(dataset, "Table_1");  
            Console.WriteLine("插入{0}条记录时间:{1}", datatable.Rows.Count, DateTime.Now - startdate); 
        }

解决方案 »

  1.   


    最快的就是生成Insert语句,通过Command执行,可我一次执行多条而Connection只需要打开一次就可以了,所有的都执行完之后再关闭
      

  2.   

    如果采用insert语句或procedure逐行插入数据,每次都需要sqlconnection.open(),sqlconnection.close()
    ---------------
    没有人规定过“每次都需要sqlconnection.open(),sqlconnection.close()”...相反这种做法是被摈弃的...DataSet不是以性能见长的,它的优点是减少与数据源的交互...某些时候看起来性能高实际上只是因为在本机处理没有网络延时而已...就insert而言同样条件下DataSet不可能比其他方式更快...
      

  3.   

    Insert()比DataSet的update()效率高!
    特别是当数据量大了以后DataSet的update()效率就会下降!不需要 每次都需要sqlconnection.open(),sqlconnection.close()!
    楼主可以将数据整理好后,一次性进行插入。
      

  4.   

    DataSet里每一行都有一个状态,标识编辑、添加、删除。
    update()的时候一行一行的判断这一行的状态,然后对应操作。
      

  5.   

    我记得DataSet的update()是在修改大数据量时才会用到。这样不需要每次从数据库读取,修改,
    先把需要修改的数据填充到DataSet,修改完了,在把DataSet的最新数据update()到数据库,也就是批修改数据。
      

  6.   

    有什么意义呢?应该写类似于这样的代码
            using (SqlConnection sqlconn = new SqlConnection(connectionString)) 
           { 
               sqlconn.Open(); 
               DBCommand sqlcommand = sqlconn.CreateCommand();
                foreach (DataRow datarow in datatable.Rows) 
                { 
                    sqlcommand.CommandText= "INSERT INTO [Table_1]([CompanyName],[CompanyCode],[Address],[Owner],[Memo])" + 
                              "VALUES('" + datarow["CompanyName"].ToString() + "'" + 
                              ",'" + datarow["CompanyCode"].ToString() + "'" + 
                              ",'" + datarow["Address"].ToString() + "'" + 
                              ",'" + datarow["Owner"].ToString() + "'" + 
                              ",'" + datarow["Memo"].ToString() + "')"; 
                    sqlcommand.ExecuteNonQuery(); 
                } 
           }  //没有必要写 sqlconn.Close(),写了反而是多余浪费了CPU时间。
      

  7.   

    如果你对“速度”有什么疑问,那么很可能源于你对功能的理解方面。例如你的所谓insert代码根本没有考虑到ACID的安全问题。
      

  8.   

    每次都insert的话
    参数写起来麻烦
    不如用DataTable
    再用sqlcommandbuilder和sqldataadapter
    用sqldataadapter的update来做啊
    把需要插入数据库的行SetAdded()一下
    再sqldataadapter.update(datatable)
    要是要求效率的话,在执行之前设置一下sqlconnection的事务,执行完毕就提交
      

  9.   

    insert效率高,SqlDataAdapter需要根据内存中DataTable的更改生成相应的SqlCommand语句,再执行,所以如果数据量大的话,会很慢的
      

  10.   

    另外,例如很明显地,你的代码(以及我上面复制你的代码)根本没有考虑SQL命令基本的语法——当字符串中包含单引号时的处理(但是update()绝对没有这个问题)。这个关于单引号的处理经常被一些人误认为是所谓“SQL注入问题”,其实这就是连基本的SQL语法都没有符合。因此你的代码不但有功能,而且有逻辑bug。虽然自己写低级的代码会“快”一些,但是当你连正确性都没能保证,还是尽量使用.net框架现成封装好的一步到位的简单代码,不要自己写很低级的代码。一个产品中写的低级代码越多,并不代表开发者水平越高,顶多代表开发者属于中等。好的开发者很少写多余的代码。
      

  11.   

    我觉得用insert还快一些!!!
      

  12.   

    顶老大,我也推荐使用using语句,自动清除垃圾,既然有了using 何必又加了close()??
      

  13.   

    推荐使用存储过程或者SqlBulkCopy来加载其他数据源
      

  14.   

    几乎不使用DATESET这种高级控件了,虽然很实用,
    现在一般就是DbReader直接到泛型集合里去
      

  15.   

    DataAdapter.Update的性能远远优于Insert.
    请关注DataAdapter的UpdateBatchSize属性.UpdateBatchSize用于获取设置每次使用DataAdapter.Update()更新时的条数.
    使用 UpdateBatchSize 属性用来自 DataSet 的更改更新数据源。如果数据提供程序支持批处理,将可以提高应用程序的性能,这是因为到服务器的往返过程的次数减少了。在 ADO.NET 2.0 中,对用于 SQL Server (SqlClient) 和 Oracle (OracleClient) 的 .NET 数据提供程序支持此属性。 UpdateBatchSize值不能设置过大,执行极大规模的批处理会降低性能。因此,在实现应用程序前应进行测试以得到最佳的批大小。 该UpdateBatchSize值默认为1.
      

  16.   


    //使用insert 
                startdate = DateTime.Now; 
                foreach (DataRow datarow in datatable.Rows) 
                { 
                    string sql = "INSERT INTO [Table_1]([CompanyName],[CompanyCode],[Address],[Owner],[Memo])" + 
                              "VALUES('" + datarow["CompanyName"].ToString() + "'" + 
                              ",'" + datarow["CompanyCode"].ToString() + "'" + 
                              ",'" + datarow["Address"].ToString() + "'" + 
                              ",'" + datarow["Owner"].ToString() + "'" + 
                              ",'" + datarow["Memo"].ToString() + "')"; 
                    using (SqlConnection sqlconn = new SqlConnection(connectionString)) 
                    { 
                        sqlconn.Open(); 
                        SqlCommand sqlcommand = new SqlCommand(sql, sqlconn); 
                        sqlcommand.ExecuteNonQuery(); 
                        sqlconn.Close(); 
                    } 
                } 
                Console.WriteLine("插入{0}条记录时间:{1}", datatable.Rows.Count, DateTime.Now - startdate); 
    不应该在循环中每次打开关闭数据库,应该放在循环的外面开关一次就可以了
      

  17.   

    dataadapter应该也就是调用的 insert 吧~~~
    感觉上两者不会相差多少,
    还有,不用每次都 打开数据库啊,打开一次就行了
      

  18.   

    问题已经解决了,大家可以去看看我博客上的文章,同时上面有我的测试记录。
    地址如下:
    http://blog.csdn.net/humozhi/archive/2009/03/31/4039868.aspx
      

  19.   

    有两个问题  
    1 能不能支持连表查询
    2 连表后的查出的数据 可能没有主键 或者没有唯一标识 
    以上两点 是不是智能用 insert来解决
      

  20.   

    把sqlconnection.close()放到最后不就行了?为什么要每次都关?