2012-04-19 22 views
10

Tôi đang mã hóa để đọc các tệp xml để cập nhật cơ sở dữ liệu. Tôi nhận được khoảng 500 tệp xml và tôi muốn xử lý chúng nhanh nhất có thể.Có thể thực hiện nhiều thủ tục được lưu trữ trong một thao tác đơn lẻ không?

Tất cả các thao tác cơ sở dữ liệu được thực hiện bằng quy trình được lưu trữ.

Có khoảng 35 thủ tục được lưu trữ khác nhau được gọi cho mỗi tệp xml.

Ban đầu tôi đã viết đoạn code như thế này

var cmd = new SqlCommand("EXEC UpdateTeamStats("+teamId+","+points+")"); 
cmd.CommandType = CommandType.Text; 

nhưng sau khi trải qua một số thông lệ tốt nhất mà tôi đã thay đổi nó để

var cmd = new SqlCommand("UpdateTeamStats"); 
cmd.CommandType = CommandType.StoredProcedure; 
cmd.Parameters.Add("teamId", 21); 
cmd.Parameters.Add("points", 2); 

vì số lượng lớn các thủ tục lưu trữ được gọi từ chương trình Tôi nhận ra rằng tôi phải thực hiện số cuộc gọi ít hơn để tối ưu hóa.

Vì vậy, tôi muốn thu thập tất cả 35 thủ tục được lưu trữ cùng nhau và thực hiện chúng trong một lần.

Các thủ tục được lưu trữ khác với các tham số khác nhau và tôi không biết cách thu thập và thực thi chúng cùng nhau sau khi thay đổi tham số tôi đã làm ở trên.

Tôi đã nghĩ đến việc gọi một thủ tục lưu trữ khổng lồ và bên trong thủ tục lưu trữ gọi 35 khác, nhưng tôi không giỏi SQL và nó sẽ dẫn đến sự phức tạp không cần thiết.

Có thể thực hiện điều này hoàn toàn trong C# không?

Hoặc là có một số phương pháp khác tốt hơn để xếp hàng lên storedprocedures và chạy chúng một cách nhanh chóng

+0

gì làm bạn mong đợi xảy ra khi ở giữa việc thực hiện của bạn, một lỗi đã xảy ra? Tất cả các thủ tục thực hiện rollback? Hoặc chỉ cần tiếp tục xử lý các thủ tục còn lại? –

+0

Lưu ý rằng tiêu đề của bạn nói "song song" nhưng đọc câu hỏi của bạn, có vẻ như bạn chỉ có nghĩa là "một lệnh cơ sở dữ liệu" –

+0

@GeorgeDuckett - Đó là chỉnh sửa của tôi. Bản gốc là "trong một lần". – Oded

Trả lời

0

Bạn có thể tạo một CommandQueue, qua Command pattern và tạo ra một đại biểu vào lệnh mà các bản đồ để bất cứ điều gì yêu cầu của bạn là dành cho các cuộc gọi để các thủ tục được lưu trữ; bởi ngoại hình, một cái gì đó như:

public class CommandQueue 
{ 
    private Connection _connexion = new Connection(); // Set this up somehow. 

    // Other methods to handle the concurrency/ calling/ transaction etc. 

    public Func<string, Dictionary<string, int>, bool> CallStoredProcedure = (procedureName, parameterValueMap) => 
    { 
     cmd.Connection = GetConnexion(); 
     var cmd = new SqlCommand(procedureName); 
     cmd.CommandType = CommandType.StoredProcedure; 

     foreach (var parameterValueMapping in parameterValueMap) 
     { 
     cmd.Parameters.Add(parameterValueMapping.Key, parameterValueMapping.Value); 
     } 

     var success = cmd.ExecuteNonQuery(); 

     return success; 
    } 

    private Connection GetConnexion() 
    { 
     return _connexion; 
    } 
} 

Và sau đó, thiết lập các CommandQueue, do đó bạn có một thread pool, từ đó bạn có thể gọi các đại biểu về một chủ đề mới, để họ chạy song song.

Thực ra, nhìn vào lớp SQLCommand, bạn có thể thực hiện cuộc gọi không đồng bộ trên đó. Vì vậy, bạn sẽ có thể gọi từng thủ tục được lưu trữ của bạn một cách không đồng bộ, thiết lập một đại biểu cho mỗi khi hoàn thành và bọc tất cả trong một giao dịch, để bạn có thể cuộn chúng trở lại khi bạn cần bằng cách gọi Cancel() trên mỗi lệnh. Tôi có lẽ vẫn sẽ sử dụng một số CommandQueue để tóm tắt điều này, vì tôi đề nghị bạn có thể sẽ thay đổi nó sau!

Tôi nghĩ rằng tôi vẫn gói gọn thủ tục lưu trữ với một đại biểu trên CommandQueue, để tóm tắt chi tiết của proc được lưu trữ và làm cho quá trình dễ hiểu hơn cho bất kỳ ai khác và dễ bảo trì hơn. Nó sẽ dễ dàng hơn nhiều nếu bạn thêm procs được lưu trữ mới, hoặc thay đổi tên, hoặc một cái gì đó. Bạn có thể thiết lập một danh sách tĩnh có thể chứa tất cả các đại biểu, hoặc một danh sách tĩnh với các chi tiết thủ tục được lưu trữ cần thiết và sử dụng ủy nhiệm để truyền vào chỉ các tham số.

1

Vui lòng tải Microsoft khối ứng dụng dữ liệu từ

http://www.microsoft.com/download/en/details.aspx?id=435

Fine, Nhưng làm thế nào để sử dụng nó?

Việc sử dụng lớp trình bao bọc này khá đơn giản.

DAC DC = new DAC(); 
DC.StoredProcedure = "nProc_InsertOrder"; 
DC.Params.Add("@OrderId", SqlDbType.VarChar, "Order1"); 
DC.Params.Add("@CustomerName", SqlDbType.VarChar, "test"); 
DAC.Commands.Add(DC); 

DC = new DAC(); 
DC.StoredProcedure = "nProc_InsertOrderLineItems"; 
DC.Params.Add("@OrderId", SqlDbType.VarChar, "Order1"); 
DC.Params.Add("@OrderLineId", SqlDbType.VarChar, "A1"); 
DAC.Commands.Add(DC); 

DC = new DAC(); 
DC.StoredProcedure = "nProc_InsertOrderLineItems"; 
DC.Params.Add("@OrderId", SqlDbType.VarChar, "Order1"); 
DC.Params.Add("@OrderLineId", SqlDbType.VarChar, "A2"); 
DAC.Commands.Add(DC); 

DC = new DAC(); 
DC.StoredProcedure = "nProc_CreateBill"; 
DC.Params.Add("@BillDate", SqlDbType.DateTime, DateTime.Now); 
DC.Params.Add("@BillId", SqlDbType.VarChar, "Bill1"); 
DAC.Commands.Add(DC); 
DAC.ExecuteBatch(); 

Nếu không thể chèn đơn đặt hàng, hóa đơn sẽ không được tạo. Tương tự, nếu các chi tiết đơn hàng không thành công, thì đơn đặt hàng sẽ không được tạo. Chúng tôi đang đạt được điều này chỉ trong một vài dòng mã thông qua ADO.Net.

Trong ví dụ này, cho đến khi chúng tôi gọi ExecuteBatch, chúng tôi không thực sự chèn các bản ghi nhưng chuẩn bị đối tượng để thực hiện cập nhật lô.

+0

Đối tượng DAC chính đến từ đâu - đối tượng chúng tôi đang sử dụng cho 'DAC.Commands.Add'? Nó không thể tĩnh khác điều này sẽ không được thread-an toàn! Và điều này thực sự làm những gì chúng ta muốn ở đây - không có sự hỗ trợ rõ ràng từ các lớp máy khách SQL Server, điều này thực sự chỉ làm một vòng tròn DB đơn hay thay thế tất cả các lệnh trong một giao dịch? – Rup

+0

Chúng tôi đang gói tất cả các lệnh trong một đối tượng duy nhất và thực hiện chúng trong một kết nối mở duy nhất với giao dịch. –

1

Giải pháp tốt nhất là viết một thủ tục được lưu trữ với tham số bảng có giá trị được truyền trong đó chứa danh sách tất cả các tham số cho mỗi tệp xml. Sau đó, trong proc được lưu trữ, hãy gọi tất cả các procs được lưu trữ khác cho mỗi bản ghi trong tham số có giá trị bảng.

Nếu điều này không ổn, bạn có thể sử dụng SqlCommand của văn bản kiểu thay vì thủ tục lưu sẵn và chỉ cần xây dựng lệnh khi bạn đi và thực hiện nó. Bạn có thể sử dụng các tham số như bạn làm bây giờ hoặc bạn chỉ có thể viết sql động.

0

Cá nhân, và trong kinh nghiệm của tôi sử dụng ADO.NET, tôi nghĩ rằng bạn sẽ không có vấn đề nào thực hiện những như báo cáo riêng biệt sử dụng một đơnSqlConnection.

Điều này có lợi ích của việc tận dụng tuyệt vời của .NET connection pooling, cho phép bạn làm việc/tùy chỉnh/tương tác với từng lệnh riêng lẻ và kết nối chia sẻ (giảm số lượng kết nối môi giới với số lượng nhỏ).

Tôi cũng muốn nhấn mạnh điều quan trọng của các điều khoản using ở đây để tạo thuận lợi cho việc xử lý thích hợp các tài nguyên khác nhau.

Ví dụ:

using (var conn = new SqlConnection("connection string")) 
{ 
    using (var cmd = new SqlCommand()) 
    { 
     cmd.Connection = conn; 
     cmd.CommandType = CommandType.StoredProcedure; 

     //ready to query 
     conn.Open(); 

     cmd.CommandText = "UpdateTeamStats"; 
     var teamIdParam = new SqlParameter("teamId", 21); 
     var pointsParam = new SqlParameter("points", 2); 

     cmd.Parameters.Add(teamIdParam); 
     cmd.Parameters.Add(pointsParam); 

     cmd.ExecuteNonQuery(); //OR if you're async cmd.ExecuteNonQueryAsync(); 

     //the rest of your executions 

     conn.Close(); 
    } 
} 

Và nếu tôi là ân cần trong một khoảnh khắc, bạn có thể sử dụng thư viện, như tôi DbConnect, làm giảm ở trên để:

using (var db = new DbConnect("connection string")) 
{ 
    db.SetSqlCommand("UpdateTeamStats"); 
    db.AddParameter("teamId", 21); 
    db.AddParameter("points", 2); 

    db.ExecuteNonQuery().Wait(); //OR if youre async await db.ExecuteNonQuery(); 

    db.ClearParameters(); 
    db.SetSqlCommand("some other proc"); 

    //rest of executions 
} 
Các vấn đề liên quan