2012-05-01 38 views
22

Tôi có một DataTable và cần toàn bộ điều được đẩy vào một bảng Cơ sở dữ liệu.Chèn toàn bộ DataTable vào cơ sở dữ liệu cùng một lúc thay vì từng hàng?

Tôi có thể nhận được tất cả trong đó với một foreach và chèn mỗi hàng tại một thời điểm. Điều này đi rất chậm mặc dù kể từ khi có một vài nghìn hàng.

Có cách nào để thực hiện toàn bộ dữ liệu cùng một lúc có thể nhanh hơn không?

DataTable có ít cột hơn bảng SQL. phần còn lại của họ nên được để lại NULL.

+4

SqlBulkCopy chắc chắn là một con đường để đi –

+0

http://www.codedigest.com/Articles/Framework/388_Doing_Bulk_UploadInsert_of_DataTable_to_a_Table_in_SQL_server_in_C_.aspx cho một SqlBulkCopy thí dụ. – JamieSee

+2

Bạn có thể vui lòng chỉ định phiên bản SQL Server nào không? –

Trả lời

48

Tôi phát hiện ra SqlBulkCopy là một cách dễ dàng để thực hiện việc này và không yêu cầu thủ tục lưu trữ được ghi trong SQL Server.

Dưới đây là một ví dụ về cách tôi thực hiện nó:

// take note of SqlBulkCopyOptions.KeepIdentity , you may or may not want to use this for your situation. 

using (var bulkCopy = new SqlBulkCopy(_connection.ConnectionString, SqlBulkCopyOptions.KeepIdentity)) 
{ 
     // my DataTable column names match my SQL Column names, so I simply made this loop. However if your column names don't match, just pass in which datatable name matches the SQL column name in Column Mappings 
     foreach (DataColumn col in table.Columns) 
     { 
      bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName); 
     } 

     bulkCopy.BulkCopyTimeout = 600; 
     bulkCopy.DestinationTableName = destinationTableName; 
     bulkCopy.WriteToServer(table); 
} 
+4

@AaronBertrand Tôi đã có câu trả lời trước đó chỉ là "Sao chép số lượng lớn SQL", không có chi tiết. Tôi đã xóa nó và thay thế bằng chi tiết này. Trong nhiều trường hợp, không cần thiết phải có SP, trong một số trường hợp. Tôi không bao giờ nói rằng nó là xấu, tôi chỉ cung cấp một giải pháp mà không cần nó. – Kyle

+0

Đối với hậu thế, bạn nên chỉnh sửa câu trả lời như vậy, thay vì xóa nó và đăng một câu trả lời mới. Sau đó, nó trực quan hơn với những người khác, nơi câu trả lời mới này đến từ đó. –

+6

Tôi không chắc chắn câu trả lời đến từ vấn đề gì, nếu không có thông tin hữu ích trong đó. Lý do tôi tạo ra một cái mới, là bởi vì bình luận không còn ý nghĩa với câu trả lời được sửa lại, và không có liên quan gì đến câu hỏi đó. – Kyle

27

Vì bạn có một DataTable đã có, và kể từ khi tôi giả sử bạn đang sử dụng SQL Server 2008 hoặc cao hơn, điều này có lẽ là cách đơn giản nhất. Thứ nhất, trong cơ sở dữ liệu của bạn, tạo ra hai đối tượng sau:

CREATE TYPE dbo.MyDataTable -- you can be more speciifc here 
AS TABLE 
(
    col1 INT, 
    col2 DATETIME 
    -- etc etc. The columns you have in your data table. 
); 
GO 

CREATE PROCEDURE dbo.InsertMyDataTable 
    @dt AS dbo.MyDataTable READONLY 
AS 
BEGIN 
    SET NOCOUNT ON; 

    INSERT dbo.RealTable(column list) SELECT column list FROM @dt; 
END 
GO 

Bây giờ trong mã # C:

DataTable tvp = new DataTable(); 
// define/populate DataTable 

using (connectionObject) 
{ 
    SqlCommand cmd = new SqlCommand("dbo.InsertMyDataTable", connectionObject); 
    cmd.CommandType = CommandType.StoredProcedure; 
    SqlParameter tvparam = cmd.Parameters.AddWithValue("@dt", tvp); 
    tvparam.SqlDbType = SqlDbType.Structured; 
    cmd.ExecuteNonQuery(); 
} 

Nếu bạn đã cho thông tin chi tiết cụ thể hơn trong câu hỏi của bạn, tôi sẽ có được một cụ thể hơn câu trả lời.

+0

Nếu tôi không nhầm, điều này sẽ chỉ hoạt động một cách đáng kể với lượng dữ liệu tương đối nhỏ, vì @dt sẽ được điền hàng theo hàng. 'SqlBulkCopy' là hiệu quả hơn cho dữ liệu lớn (hàng nghìn và nhiều hơn nữa). – Alexei

+0

@Aaron Bertrand Tôi có tất cả hơn 600000 bản ghi chèn cho 3 bảng khác nhau. Bảng A không phụ thuộc vào bất kỳ bảng nào khác trong khi Bảng B cần khóa chính từ Bảng A và Bảng C cần giá trị khóa chính từ A và B. Ngoài ra, Bảng D cần 10.000 bản cập nhật. Làm thế nào tôi có thể đạt được điều này. – User

0

Tôi muốn sử dụng kiểu dữ liệu được định nghĩa: đó là siêu nhanh.

Bước 1: Tạo User Defined Bảng trong Sql Server DB

CREATE TYPE [dbo].[udtProduct] AS TABLE(
    [ProductID] [int] NULL, 
    [ProductName] [varchar](50) NULL, 
    [ProductCode] [varchar](10) NULL 
) 
GO 

Bước 2: Tạo Stored Procedure với User Defined Loại

CREATE PROCEDURE ProductBulkInsertion 
@product udtProduct readonly 
AS 
BEGIN 
    INSERT INTO Product 
    (ProductID,ProductName,ProductCode) 
    SELECT ProductID,ProductName,ProductCode 
    FROM @product 
END 

Bước 3: Thực hiện thủ tục được lưu trữ từ C#

SqlCommand sqlcmd = new SqlCommand("ProductBulkInsertion", sqlcon); 
sqlcmd.CommandType = CommandType.StoredProcedure; 
sqlcmd.Parameters.AddWithValue("@product", productTable); 
sqlcmd.ExecuteNonQuery(); 

vấn đề có thể: Thay đổi User Defined Table

Trên thực tế không có lệnh sql server để thay đổi người sử dụng định nghĩa kiểu Nhưng trong studio quản lý bạn có thể đạt được điều này từ bước sau

1.tạo tập lệnh cho loại. (Trong cửa sổ truy vấn mới hoặc dưới dạng tệp) 2.xóa bảng thách thức của người dùng. 3. sửa đổi kịch bản tạo và sau đó thực hiện.

1

Nếu có thể đi chệch một chút từ con đường thẳng của DataTable -> bảng SQL, nó cũng có thể được thực hiện thông qua một danh sách các đối tượng:

1) DataTable -> Danh sách chung của các đối tượng

public static DataTable ConvertTo<T>(IList<T> list) 
{ 
    DataTable table = CreateTable<T>(); 
    Type entityType = typeof(T); 
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType); 

    foreach (T item in list) 
    { 
     DataRow row = table.NewRow(); 

     foreach (PropertyDescriptor prop in properties) 
     { 
      row[prop.Name] = prop.GetValue(item); 
     } 

     table.Rows.Add(row); 
    } 

    return table; 
} 

Nguồn và biết thêm chi tiết có thể được tìm thấy here. tính thiếu sẽ vẫn để giá trị mặc định của họ (0 cho int s, null với nhiều loại tài liệu tham khảo, vv)

2) Đẩy đối tượng vào cơ sở dữ liệu

Một cách là sử dụng EntityFramework.BulkInsert mở rộng. Mặc dù vậy, dữ liệu địa lý EF là bắt buộc.

Nó tạo ra lệnh BULK INSERT cần thiết để chèn nhanh (giải pháp loại bảng do người dùng định nghĩa chậm hơn nhiều so với điều này).

Mặc dù không phải là phương pháp thẳng, nó giúp xây dựng cơ sở làm việc với danh sách các đối tượng thay vì DataTable s trong đó seems to be much more memory efficient.

3

Cân nhắc this approach, bạn không cần một vòng lặp for:

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) 
{ 
    bulkCopy.DestinationTableName = 
     "dbo.BulkCopyDemoMatchingColumns"; 

    try 
    { 
     // Write from the source to the destination. 
     bulkCopy.WriteToServer(ExitingSqlTableName); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.Message); 
    } 
} 
+0

cho người mới như tôi: bulkCopy.WriteToServer (ExitingSqlTableName); Ở đây ExistingSqlTableName có nghĩa là nguồn dữ liệu sql hiện có. Nó có thể là một bảng sql, datatable hoặc một người đọc. – Goldfish

Các vấn đề liên quan