2015-11-03 76 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(); 
       } 
      } 
     } 
    } 
}