2015-11-03 79 views
6

我有一个包含数十万行的DataTable。通过我的过程,我为这个DataTable添加了几千行,这些行也需要添加到数据库中。我不想为每条记录创建INSERT语句,而是尽可能快地插入它们。 MySQL LOAD INTO命令不适用,因为我不想涉及任何外部CSV文件。插入多行的最快方法

我迄今所做的,是用一个MySqlDataAdapter和所说的“更新”的方法只有插入的变化,就像这样:

MySqlCommandBuilder commandBuilder = new MySqlCommandBuilder(adapter); 
adapter.InsertCommand = commandBuilder.GetInsertCommand(); 
adapter.Update(myDataTable); 

这也运行十分缓慢,所以我怀疑他们一次也插入一行。我有什么选择?构建一个包含所有值的长INSERT语句,唯一的出路?

+0

确实是帮助手动启动交易,在更新前? – Jens

+0

@Thomas - 批量插入似乎只能在MySQL中使用外部文件,但是正确吗? –

回答

2

,我看到的是唯一的解决办法:

1)转换数据表到csv->你可以google一下。

2)将其保存在服务器端的临时目录中。

3)使用MySqlBulkLoader这里是link关于它的文章。加载保存在临时目录中的文件。

4)之后,从临时目录中删除文件。

+0

虽然我一直都知道这个选择,这是我最终采取的方法,因为没有其他明显的方式来做我想做的事情。所以谢谢你确认这是一条路。 –

5

插入值这样的: -

INSERT INTO tbl_name 
    (a,b,c) 
VALUES 
    (1,2,3), 
    (4,5,6), 
    (7,8,9); 

为了优化插入速度,并结合大量的小规模经营成一个单一的 大的操作。

+0

这怎么能通过参数化查询完成?它能够支持数十万条记录吗? –

+0

你在列上有索引吗? – avrono

+0

并非所有的人都被编入索引@avrono –

0

我不知道这是否是一个有参数的好方法,但效果很好 该方法接收“ParamDbList”(ParamDB集合)列表并插入每1000个寄存器或1900个参数(限制为2000)的行。就在这个适应您的驱动器

public bool InsertBatch(System.Collections.Generic.List<ParamDbLIST> dados, string tabela) 
    { 
     if (dados.Count == 0) 
      return true; 

     string campos = ""; 
     dados[0].ForEach(delegate(ParamDB p) 
     { 
      campos += (campos == "" ? "" : ", ") + "@" + p.sNOME + "#N#"; 
     }); 

     bool resultado = true; 
     //Insere de 999 a 999, que é o máximo q o sql server permite por vez 
     //Maximo de 2000 parametros 
     int k = 0; 
     while (k < dados.Count) 
     { 
      this.sql = new StringBuilder(); 
      List<String> vals = new List<string>(); 
      ParamDbLIST parametros_insert = new ParamDbLIST(); 
      int c_sqls = 0; 
      int c_parametros = 0; 
      while (k < dados.Count && c_sqls < 1000 && c_parametros < 1900) 
      { 
       c_sqls++; 
       vals.Add("(" + campos.Replace("#N#", c_sqls.ToString()) + ")"); 
       foreach (ParamDB p in dados[k]) 
       { 

        p.sNOME += c_sqls.ToString(); 
        parametros_insert.Add(p); 
        c_parametros++; 
       } 
       k++; 
      } 

      this.sql.Append("INSERT INTO " + tabela + "(" + campos.Replace("#N#", String.Empty).Replace("@", String.Empty) + ") VALUES " + String.Join(",", vals)); 

      resultado = resultado && this.RunSQL(sql.ToString(), parametros_insert); 

     } 

     return resultado; 
    } 






public class ParamDbLIST : System.Collections.ObjectModel.Collection<ParamDB> 
{/*I have other stuff here, but this will work*/} 

    public class ParamDB 
{ 
    public string sNOME { get; set; } 
    public Object sVALOR { get; set; }} 

记住的方法 INSERT INTO tbl_name (A,B,C) VALUES (1,2,3), (4,5,6), ( 7,8,9);每个命令的 限制为1000行。

我觉得是一件好事,在这里做将使用事务(对于安全)

你应该改变的是RunSQL

如果此方法可以进行优化,请让该方法我知道

0

不确定MySQL,但我发现与SQL服务器迄今为止插入的最快方式类似于@Rahautos,但将值列表分隔为单独的查询。 我知道这听起来很奇怪,但是这使得速度从每秒1200到12000次插入速度提高了10倍。 不知道有什么区别。 交易也非常有帮助。

INSERT INTO tbl_name 
    (a,b,c) 
VALUES 
    (1,2,3); 
INSERT INTO tbl_name 
    (a,b,c); 
VALUES 
    (4,5,6); 
INSERT INTO tbl_name 
    (a,b,c); 
VALUES 
    (7,8,9); 

示例代码

using System; 
using System.Collections.Generic; 
using System.Data.SqlClient; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var constring = (new SqlConnectionStringBuilder 
      { 
       DataSource = "someserver", 
       InitialCatalog = "12trunk", 
       IntegratedSecurity = true 
      }).ToString(); 
      using (var con = new SqlConnection(constring)) 
      { 
       con.Open(); 
       using (var trans = con.BeginTransaction(isolationLevel: System.Data.IsolationLevel.ReadUncommitted) as SqlTransaction) 
       using (var cmd = new SqlCommand()) 
       { 
        cmd.Transaction = trans; 
        cmd.Connection = con; 
        var start = DateTime.Now; 
        Console.WriteLine("Start = " + start); 
        const int inserts = 100000; 
        var builder = new StringBuilder(); 
        cmd.CommandText = "delete from test";      
        for (int i = 0; i < inserts; i++) 
        { 
         Guid[] guids = new Guid[7]; 
         for (int j = 0; j < 7; j++) 
         { 
          guids[j] = Guid.NewGuid(); 
         } 
         var sql = $"insert into test (f0, f1, f2, f3, f4, f5, f6) values ('{guids[0]}', '{guids[1]}', '{guids[2]}','{guids[3]}', '{guids[4]}', '{guids[5]}', '{guids[6]}');\n"; 
         builder.Append(sql); 
         if (i % 1000 == 0) 
         { 
          cmd.CommandText = builder.ToString(); 
          cmd.ExecuteNonQuery(); 
          builder.Clear(); 
         } 

        } 
        cmd.CommandText = builder.ToString(); 
        cmd.ExecuteNonQuery(); 
        trans.Commit(); 
        var ms = (DateTime.Now - start).TotalMilliseconds; 
        Console.WriteLine("Ms to run = " + ms); 
        Console.WriteLine("inserts per sec = " + inserts/(ms/1000)); 
        Console.ReadKey(); 
       } 
      } 
     } 
    } 
}