2010-07-29 28 views
5

Vì vậy, tôi đang làm việc trên một cơ sở dữ liệu mà tôi sẽ bổ sung cho các dự án tương lai của mình như một db hỗ trợ, nhưng tôi có một chút vấn đề với nó, đặc biệt là các bản ghi.Sql Server 2008 Điều chỉnh với các giao dịch lớn (700k + hàng/giao dịch)

Cơ sở dữ liệu về cơ bản cần được cập nhật mỗi tháng một lần. Bảng chính phải được thanh lọc và sau đó nạp lại một tệp CSV. Vấn đề là Sql Server sẽ tạo ra một bản ghi cho nó là MEGA lớn. Tôi đã thành công trong việc lấp đầy nó một lần, nhưng muốn kiểm tra toàn bộ quá trình bằng cách thanh lọc nó và sau đó bơm lại nó.

Đó là khi tôi gặp lỗi khi tệp nhật ký được lấp đầy. Nó nhảy từ 88MB (sau khi thu nhỏ thông qua kế hoạch bảo trì) đến 248MB và sau đó dừng quá trình hoàn toàn và không bao giờ hoàn thành.

Tôi đã giới hạn tốc độ tăng trưởng là 256MB, tăng 16MB, đó là lý do tại sao nó không thành công, nhưng trên thực tế, tôi không cần nó để ghi lại bất kỳ thứ gì. Có cách nào để hoàn toàn bỏ qua đăng nhập vào bất kỳ truy vấn đang chạy với cơ sở dữ liệu?

Cảm ơn bạn đã trả lời trước!

CHỈNH SỬA: Theo đề xuất của @ mattmc3 Tôi đã triển khai SqlBulkCopy cho toàn bộ quy trình. Nó hoạt động AMAZING, ngoại trừ, vòng lặp của tôi bằng cách nào đó bị rơi vào đoạn cuối cùng còn lại cần được chèn vào. Tôi không chắc chắn nơi tôi đang đi sai, heck tôi thậm chí không biết nếu đây là một vòng lặp thích hợp, vì vậy tôi sẽ đánh giá cao một số trợ giúp về nó.

Tôi biết rằng đó là vấn đề với các cuộc gọi GetDataTable hoặc SetSqlBulkCopy cuối cùng. Tôi đang cố gắng để chèn 788.189 hàng, 788.000 nhận được trong và số còn lại 189 đang đâm ...

string[] Rows; 

using (StreamReader Reader = new StreamReader("C:/?.csv")) { 
    Rows = Reader.ReadToEnd().TrimEnd().Split(new char[1] { 
     '\n' 
    }, StringSplitOptions.RemoveEmptyEntries); 
}; 

int RowsInserted = 0; 

using (SqlConnection Connection = new SqlConnection("")) { 
    Connection.Open(); 

    DataTable Table = null; 

    while ((RowsInserted < Rows.Length) && ((Rows.Length - RowsInserted) >= 1000)) { 
     Table = GetDataTable(Rows.Skip(RowsInserted).Take(1000).ToArray()); 

     SetSqlBulkCopy(Table, Connection); 

     RowsInserted += 1000; 
    }; 

    Table = GetDataTable(Rows.Skip(RowsInserted).ToArray()); 

    SetSqlBulkCopy(Table, Connection); 

    Connection.Close(); 
}; 

static DataTable GetDataTable(
    string[] Rows) { 
    using (DataTable Table = new DataTable()) { 
     Table.Columns.Add(new DataColumn("A")); 
     Table.Columns.Add(new DataColumn("B")); 
     Table.Columns.Add(new DataColumn("C")); 
     Table.Columns.Add(new DataColumn("D")); 

     for (short a = 0, b = (short)Rows.Length; a < b; a++) { 
      string[] Columns = Rows[a].Split(new char[1] { 
       ',' 
      }, StringSplitOptions.RemoveEmptyEntries); 

      DataRow Row = Table.NewRow(); 

      Row["A"] = Columns[0]; 
      Row["B"] = Columns[1]; 
      Row["C"] = Columns[2]; 
      Row["D"] = Columns[3]; 

      Table.Rows.Add(Row); 
     }; 

     return (Table); 
    }; 
} 

static void SetSqlBulkCopy(
    DataTable Table, 
    SqlConnection Connection) { 
    using (SqlBulkCopy SqlBulkCopy = new SqlBulkCopy(Connection)) { 
     SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("A", "A")); 
     SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("B", "B")); 
     SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("C", "C")); 
     SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("D", "D")); 

     SqlBulkCopy.BatchSize = Table.Rows.Count; 
     SqlBulkCopy.DestinationTableName = "E"; 
     SqlBulkCopy.WriteToServer(Table); 
    }; 
} 

EDIT/CUỐI CÙNG Mã sản phẩm: Vì vậy, các ứng dụng hiện nay là hoàn thành và các công trình tuyệt vời, và khá nhanh chóng! @ mattmc3, cảm ơn tất cả sự giúp đỡ! Đây là mã cuối cùng cho bất kỳ ai có thể thấy nó hữu ích:

List<string> Rows = new List<string>(); 

using (StreamReader Reader = new StreamReader(@"?.csv")) { 
    string Line = string.Empty; 

    while (!String.IsNullOrWhiteSpace(Line = Reader.ReadLine())) { 
     Rows.Add(Line); 
    }; 
}; 

if (Rows.Count > 0) { 
    int RowsInserted = 0; 

    DataTable Table = new DataTable(); 

    Table.Columns.Add(new DataColumn("Id")); 
    Table.Columns.Add(new DataColumn("A")); 

    while ((RowsInserted < Rows.Count) && ((Rows.Count - RowsInserted) >= 1000)) { 
     Table = GetDataTable(Rows.Skip(RowsInserted).Take(1000).ToList(), Table); 

     PerformSqlBulkCopy(Table); 

     RowsInserted += 1000; 

     Table.Clear(); 
    }; 

    Table = GetDataTable(Rows.Skip(RowsInserted).ToList(), Table); 

    PerformSqlBulkCopy(Table); 
}; 

static DataTable GetDataTable(
    List<string> Rows, 
    DataTable Table) { 
    for (short a = 0, b = (short)Rows.Count; a < b; a++) { 
     string[] Columns = Rows[a].Split(new char[1] { 
      ',' 
     }, StringSplitOptions.RemoveEmptyEntries); 

     DataRow Row = Table.NewRow(); 

     Row["A"] = ""; 

     Table.Rows.Add(Row); 
    }; 

    return (Table); 
} 

static void PerformSqlBulkCopy(
    DataTable Table) { 
    using (SqlBulkCopy SqlBulkCopy = new SqlBulkCopy(@"", SqlBulkCopyOptions.TableLock)) { 
     SqlBulkCopy.BatchSize = Table.Rows.Count; 
     SqlBulkCopy.DestinationTableName = ""; 
     SqlBulkCopy.WriteToServer(Table); 
    }; 
} 
+0

Một vài đề xuất nếu bạn muốn tăng tốc độ này nhiều hơn nữa. 1.) Thay vì làm Reader.ReadToEnd(), tạo một vòng lặp và đọc Reader.ReadLine() một dòng tại một thời điểm. Nó sẽ mất ít bộ nhớ hơn. 2.) Nếu không ai sẽ truy cập vào bảng của bạn trong thời gian bạn đang tải nó, hãy sử dụng tùy chọn 'SqlBulkCopyOptions.TableLock'. 3.) Để lưu lại một số mã, đối tượng SqlBulkCopy sẽ chèn ánh xạ cột của bạn nếu bạn đặt tên cho các cột giống như những gì trong bảng đích của bạn, và vì bạn đang xử lý chunking, không có lý do gì để thiết lập .BatchSize. Chúc mừng mã hóa! – mattmc3

+0

Về chủ đề suy luận các cột, nó sẽ hoạt động nếu: 'DBTable = {Id (PK, IDENTITY), A, B, C, D}', nhưng 'DataTable = {A, B, C, D}'? Tôi nghĩ rằng nó đã gây rắc rối cho tôi, đó là lý do tại sao tôi chỉ định cho họ, nhưng sau đó một lần nữa, tôi có thể đã được screwing nó bằng cách nào đó ... – Gup3rSuR4c

+0

Vâng, nó được thực hiện! Tôi đã triển khai mọi thứ bạn đã đề xuất và nó hoạt động tuyệt vời! Bộ nhớ đã giảm một nửa xuống còn 85MB và toàn bộ hoạt động mất khoảng 45 giây để hoàn thành. Và tôi đã tìm ra các cột ở trên, tôi đã đúng, nhưng tôi chỉ thêm một trình giữ chỗ cho 'Id' và nó hoạt động. 'THANK YOU TRỢ GIÚP TÔI VỀ NÀY VÀ CHO DẠY CHO TÔI VỀ NHỮNG ĐIỀU Tôi KHÔNG BAO GIỜ BIẾT !!!” – Gup3rSuR4c

Trả lời

5

Nếu bạn đang làm một Chèn hàng loạt vào bảng trong SQL Server, đó là cách bạn nên làm điều này (BCP, Bulk Insert, Insert Into...Select, hoặc trong .NET, lớp SqlBulkCopy), bạn có thể sử dụng "hàng loạt Logged" mô hình phục hồi. Tôi khuyên bạn nên đọc các bài viết MSDN về các mô hình khôi phục: http://msdn.microsoft.com/en-us/library/ms189275.aspx

+0

Tôi nghĩ rằng SqlBulkCopy (đó là những gì tôi sẽ được sử dụng kể từ khi hoạt động đang được thực hiện bởi một ứng dụng giao diện điều khiển) là vụ phải được sử dụng từ Bảng để bàn? – Gup3rSuR4c

+0

Ồ không ... nó từ DataTable đến một bảng SQL Server. Bạn tải dữ liệu vào một đối tượng System.Data.DataTable khớp với bảng đích của bạn. Bạn có thể lấy dữ liệu đó vào DataTable từ một tệp, từ một truy vấn, từ các đối tượng busniess của bạn ... tuy nhiên bạn muốn. Tôi khuyên bạn nên nhận được một đoạn 1000 hoặc để ghi lại trong đó, làm bản sao số lượng lớn thông qua đối tượng SqlBulkCopy, và sau đó thanh toán bù trừ DataTable ra và làm một đoạn khác. Phía sau hậu trường, đối tượng SqlBulkCopy chỉ sử dụng các cơ sở giống như một câu lệnh 'Bulk Insert'. Tôi đã làm ETL theo cách này trong nhiều năm và nó nhanh chóng và đơn giản. – mattmc3

+0

Ok. Tôi đang cố gắng viết mã bây giờ, chưa bao giờ sử dụng DataTables trước và tôi cần phải nhớ các phương pháp 'ol Sql tốt bởi vì tôi đã không sử dụng chúng kể từ khi Linq ra ... :) Dù sao, nhờ sự giúp đỡ ! – Gup3rSuR4c

1

Không có cách nào bỏ qua bằng nhật ký giao dịch trong SQL Server.

+2

Bạn phải sử dụng nhật ký - đó là sự thật. Nhưng bạn có thể giảm thiểu tác động của việc ghi nhật ký bằng cách chọn các mô hình khôi phục thay thế và chiến lược về cách bạn chèn dữ liệu của mình. – mattmc3

2

Bạn có thể đặt mô hình Khôi phục cho từng cơ sở dữ liệu riêng biệt. Có lẽ đơn giản mô hình khôi phục sẽ hoạt động cho bạn. Mẫu đơn giản:

Tự động rút lại không gian đăng nhập để giữ các yêu cầu về không gian nhỏ, về cơ bản loại bỏ nhu cầu quản lý không gian nhật ký giao dịch.

Đọc trên số here.

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