2015-11-03 16 views
6

Tôi có một số DataTable chứa hàng trăm nghìn hàng. Thông qua quá trình thủ tục của tôi, tôi đang thêm một vài nghìn hàng vào DataTable này, cần phải được thêm vào cơ sở dữ liệu. Thay vì tạo câu lệnh INSERT cho mỗi bản ghi, tôi muốn chèn chúng càng nhanh càng tốt. Lệnh MySQL LOAD INTO không phù hợp vì tôi không muốn liên quan đến bất kỳ tệp CSV bên ngoài nào.Cách nhanh nhất để chèn nhiều hàng

Những gì tôi đã làm cho đến nay, là sử dụng một MySqlDataAdapter và gọi phương thức 'Update' chỉ với những thay đổi chèn, như vậy:

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

này cũng đang chạy chậm, vì vậy tôi nghi ngờ rằng họ đang được chèn vào một hàng tại một thời điểm. Tôi có những lựa chọn nào? Đang xây dựng một tuyên bố INSERT dài với tất cả các giá trị bao gồm trong nó, cách duy nhất để đi?

+0

Liệu là giúp đỡ để bắt đầu một giao dịch bằng tay, trước khi cập nhật? – Jens

+0

@Thomas - Chèn hàng loạt chỉ có vẻ như có thể với một tệp bên ngoài trong MySQL mặc dù, đúng không? –

Trả lời

2

Giải pháp duy nhất mà tôi thấy là:

1) Chuyển đổi DataTable để csv-> bạn có thể google nó.

2) Lưu nó ở phía máy chủ trong thư mục tạm thời.

3) Sử dụng MySqlBulkLoader đây là link cho bài viết về nó. Tải tệp đã lưu trong thư mục tạm thời.

4) Sau đó xóa tệp khỏi thư mục tạm thời.

+0

Trong khi tôi biết tùy chọn này tất cả cùng, đây là cách tiếp cận tôi đã kết thúc tham gia như không có cách rõ ràng khác để làm những gì tôi muốn đạt được. Cảm ơn vì đã xác nhận rằng đây là con đường để đi. –

5

giá trị Insert như thế: -

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

Để tối ưu hóa tốc độ chèn, kết hợp nhiều hoạt động nhỏ thành một đơn hoạt động lớn.

+0

Làm thế nào điều này có thể được thực hiện với các truy vấn tham số mặc dù? Và nó sẽ có thể hỗ trợ hàng trăm ngàn hồ sơ? –

+0

Bạn có chỉ mục trên các cột không? – avrono

+0

Không phải tất cả chúng đều được lập chỉ mục @avrono –

0

tôi có thể thu thập các liên kết sau đây:

Nếu bạn muốn có một tinh khiết C# mã, sau đó kiểm tra như sau Link

Một lựa chọn khác sử dụng chunking dữ liệu -

Inserting all records from DataTable into a remote database

Nếu bạn có thể xem xét CSV có thể là một tùy chọn, sau đó có MySqlBulkLoader API

Không trông giống như MySql có song song với SqlBulkCopy API

0

Tôi không biết nếu đây là phương pháp tốt với tham số, nhưng nó hoạt động tốt Phương thức nhận danh sách "ParamDbList" (Bộ sưu tập ParamDB) và chèn hàng 1000 đăng ký hoặc 1900 tham số (giới hạn 2000). Chỉ cần thích ứng này cho ổ

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; }} 

của bạn Hãy nhớ rằng các phương pháp INSERT INTO tbl_name (a, b, c) GIÁ TRỊ (1,2,3), (4,5,6), (7,8,9); có giới hạn 1000 hàng cho mỗi lệnh.

Tôi nghĩ rằng một điều tốt để làm ở đây sẽ được sử dụng giao dịch (đối với an toàn)

Phương pháp bạn nên thay đổi được RunSQL

Nếu phương pháp này có thể được tối ưu hóa, xin vui lòng cho tôi biết

0

Không chắc chắn về MySQL nhưng tôi tìm thấy với máy chủ sql cho đến nay cách nhanh nhất để chèn là tương tự như @Rahautos nhưng để tách danh sách giá trị trong các truy vấn riêng biệt. Tôi biết nó có vẻ lạ nhưng điều này cải thiện tốc độ gấp 10 lần từ 1200 đến 12000 lần chèn mỗi giây. không chắc chắn sự khác biệt là gì. Và giao dịch cũng vô cùng hữu ích.

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); 

Ví dụ mã

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(); 
       } 
      } 
     } 
    } 
} 
Các vấn đề liên quan