2009-04-20 32 views
30

Tôi có các trình kích hoạt thao tác và chèn nhiều dữ liệu vào một bảng Thay đổi theo dõi cho mục đích kiểm tra trên mỗi lần chèn, cập nhật và xóa.Trình kích hoạt không đồng bộ trong SQL Server 2005/2008

Trình kích hoạt này thực hiện công việc của mình rất tốt, bằng cách sử dụng nó, chúng tôi có thể ghi lại giá trị cũ/giá trị mong muốn theo yêu cầu kinh doanh cho mỗi giao dịch.

Tuy nhiên, trong một số trường hợp trong đó bảng nguồn có nhiều cột, có thể mất tới 30 giây để giao dịch hoàn thành không được chấp nhận.

Có cách nào để kích hoạt chạy không đồng bộ không? Bất kỳ ví dụ nào.

+0

Thay đổi theo dõi là tính năng btw được tích hợp sẵn :) https://msdn.microsoft.com/en-us/library/bb933874.aspx – moander

Trả lời

23

Bạn không thể kích hoạt trình kích hoạt không đồng bộ, nhưng bạn có thể kích hoạt đồng bộ gửi tin nhắn đến hàng đợi SQL Service Broker. Hàng đợi sau đó có thể được xử lý không đồng bộ bởi một thủ tục được lưu trữ.

+0

Nhưng sau đó bạn vẫn đang phá vỡ kiểm soát giao dịch. – dkretz

+1

Có thể ai đó thực sự hiểu được Nhà môi giới dịch vụ giải thích liệu nhận xét ở trên ("kiểm soát giao dịch phá vỡ") có đúng không? –

+2

Để cam kết hoặc quay trở lại một giao dịch, bạn phải đợi cho đến khi mọi thứ đã thành công (để cam kết), hoặc một cái gì đó đã thất bại (để quay lại). Không đồng bộ có nghĩa là bạn không đợi nó kết thúc để tiếp tục phần còn lại của logic. – dkretz

0

Không phải là tôi biết, nhưng bạn có chèn các giá trị vào bảng Kiểm tra cũng tồn tại trong bảng cơ sở không? Nếu có, bạn có thể xem xét chỉ theo dõi những thay đổi. Do đó một chèn sẽ theo dõi thời gian thay đổi, người dùng, thêm và một bó NULL (có hiệu lực giá trị trước đó). Bản cập nhật sẽ có thời gian thay đổi, người dùng vv và giá trị trước của cột đã thay đổi. Xóa có thay đổi tại, v.v. và tất cả các giá trị.

Ngoài ra, bạn có bảng kiểm tra cho mỗi bảng cơ sở hoặc một bảng kiểm tra cho DB không? Tất nhiên sau này có thể dễ dàng hơn dẫn đến chờ đợi khi mỗi giao dịch cố gắng ghi vào một bảng.

1

Tôi tự hỏi nếu bạn có thể tag một kỷ lục cho việc theo dõi sự thay đổi bằng cách chèn vào một bảng "quá trình" bao gồm cả những người đã làm thay đổi vv vv

Sau đó, quá trình khác có thể đi cùng và sao chép phần còn lại của dữ liệu một cách thường xuyên.

2

Có một xung đột cơ bản giữa "thực hiện công việc của mình rất tốt" và "không thể chấp nhận", rõ ràng.

Nghe có vẻ như tôi đang cố gắng sử dụng các trình kích hoạt giống như cách bạn sử dụng các sự kiện trong một ứng dụng thủ tục OO, mà IMHO không ánh xạ.

Tôi sẽ gọi bất kỳ lôgic kích hoạt nào mất 30 giây - không, nhiều hơn 0,1 giây - là không hoạt động. Tôi nghĩ rằng bạn thực sự cần phải thiết kế lại chức năng của bạn và làm điều đó một cách khác. Tôi muốn nói "nếu bạn muốn làm cho nó không đồng bộ", nhưng tôi không nghĩ rằng thiết kế này có ý nghĩa trong bất kỳ hình thức nào.

Theo "trình kích hoạt không đồng bộ", xung đột cơ bản cơ bản là bạn không bao giờ có thể bao gồm một điều như vậy giữa câu lệnh BEGIN TRAN và COMMIT TRAN vì bạn đã mất dấu liệu nó có thành công hay không.

+0

Bạn đã nhận xét ở trên rằng việc sử dụng Nhà môi giới dịch vụ là "vẫn phá vỡ kiểm soát giao dịch". Tôi đã không sử dụng dịch vụ môi giới, nhưng nó sẽ không được giao dịch? –

+0

Nó không thể là nếu nó không đồng bộ. Nó không thể được tổ chức trong một giao dịch nếu bạn không chờ đợi cho nó để kết thúc để tìm hiểu xem nó đã thành công, để biết có nên cam kết hoặc cuộn ack. – dkretz

+0

Tôi xin lỗi vì đã chia nhỏ cuộc hội thoại này giữa hai đường dẫn nhận xét. Tôi nghĩ rằng nếu SB có thể cho phép khôi phục từ hàng đợi, thì đó sẽ là giao dịch. Một khi bạn đã viết nó vào hàng đợi, bạn xem nó thành công. Bạn thực hiện một điểm tốt, nhưng tôi sẽ xem nó như là một vấn đề thiết kế/định nghĩa hơn (giả sử rằng ghi vào hàng đợi SB có thể được khôi phục như một phần của giao dịch tổng thể). –

0

Tôi nghi ngờ trình kích hoạt của bạn là của các trình kích hoạt tạo csv/văn bản chung này được thiết kế để ghi lại tất cả các thay đổi cho tất cả bảng ở một nơi. Tốt về lý thuyết (có lẽ ...), nhưng khó duy trì và sử dụng trong thực tế.

Nếu bạn có thể chạy không đồng bộ (sẽ vẫn yêu cầu lưu trữ dữ liệu ở đâu đó để đăng nhập lại sau), thì bạn không kiểm tra và không có lịch sử sử dụng.

Có lẽ bạn có thể xem kế hoạch thực hiện trình kích hoạt và xem bit nào là dài nhất?

Bạn có thể thay đổi cách bạn kiểm tra, theo từng bảng? Bạn có thể chia dữ liệu nhật ký hiện tại thành các bảng có liên quan.

1

Tạo bảng lịch sử. Trong khi cập nhật (/ xóa/chèn) bảng chính, chèn các giá trị cũ của bản ghi (đã xóa bảng giả trong trình kích hoạt) vào bảng lịch sử; một số thông tin bổ sung là cần thiết quá (dấu thời gian, loại hoạt động, có thể bối cảnh người dùng). Giá trị mới được giữ trong bảng trực tiếp.

Cách kích hoạt này chạy nhanh (er) và bạn có thể thay đổi hoạt động chậm để ghi nhật ký trình xem (thủ tục).

2

SQL Server 2014 giới thiệu một tính năng rất thú vị được gọi là Delayed Durability. Nếu bạn có thể chấp nhận mất một vài hàng trong trường hợp xảy ra thảm họa, giống như một sự cố máy chủ, bạn thực sự có thể tăng hiệu suất của bạn trong các schenarios như của bạn.

Độ trễ giao dịch bị trì hoãn được thực hiện bằng nhật ký không đồng bộ ghi vào đĩa. Bản ghi nhật ký giao dịch được lưu trong bộ đệm và ghi vào đĩa khi bộ đệm đầy hoặc sự kiện xả bộ đệm mất . Độ trễ giao dịch bị trì hoãn làm giảm cả thời gian trễ và tranh chấp trong hệ thống

Cơ sở dữ liệu chứa bảng trước tiên phải được thay đổi để cho phép độ trễ bị trễ.

ALTER DATABASE dbname SET DELAYED_DURABILITY = ALLOWED 

Sau đó, bạn có thể kiểm soát độ bền trên cơ sở mỗi giao dịch.

begin tran 

insert into ChangeTrackingTable select * from inserted 

commit with(DELAYED_DURABILITY=ON) 

Giao dịch sẽ được cam kết bền nếu giao dịch là cơ sở dữ liệu chéo, vì vậy điều này sẽ chỉ hoạt động nếu bảng kiểm tra của bạn nằm trong cùng cơ sở dữ liệu như trình kích hoạt.

Cũng có khả năng thay đổi cơ sở dữ liệu là bị ép thay vì được cho phép. Điều này gây ra tất cả các giao dịch trong cơ sở dữ liệu để trở thành trì hoãn bền.

ALTER DATABASE dbname SET DELAYED_DURABILITY = FORCED 

Để có độ bền chậm, không có sự khác biệt giữa một bị tắt đột ngột và tắt máy dự kiến ​​/ khởi động lại SQL Server. Giống như sự kiện thảm khốc, bạn nên lập kế hoạch mất dữ liệu. Trong kế hoạch tắt/khởi động lại một số giao dịch chưa được ghi vào đĩa đầu tiên có thể được lưu vào đĩa, nhưng bạn không nên lên kế hoạch cho nó. Lập kế hoạch là mặc dù tắt máy/khởi động lại, dù được lập kế hoạch hoặc không có kế hoạch, mất dữ liệu giống như một sự kiện thảm khốc.

Lỗi này lạ được hy vọng sẽ được giải quyết trong bản phát hành trong tương lai, nhưng cho đến khi có thể tự động thực hiện thủ tục 'sp_flush_log' khi máy chủ SQL khởi động lại hoặc tắt.

0

Để thực hiện xử lý không đồng bộ, bạn có thể sử dụng Nhà môi giới dịch vụ, nhưng nó không phải là lựa chọn duy nhất, bạn cũng có thể sử dụng các đối tượng CLR.

Sau đây là một ví dụ về một thủ tục lưu trữ (AsyncProcedure) không đồng bộ mà các cuộc gọi một thủ tục (SyncProcedure):

using System; 
using System.Data; 
using System.Data.SqlClient; 
using System.Data.SqlTypes; 
using Microsoft.SqlServer.Server; 
using System.Runtime.Remoting.Messaging; 
using System.Diagnostics; 

public delegate void AsyncMethodCaller(string data, string server, string dbName); 

public partial class StoredProcedures 
{ 
    [Microsoft.SqlServer.Server.SqlProcedure] 
    public static void AsyncProcedure(SqlXml data) 
    { 
     AsyncMethodCaller methodCaller = new AsyncMethodCaller(ExecuteAsync); 
     string server = null; 
     string dbName = null; 
     using (SqlConnection cn = new SqlConnection("context connection=true")) 
     using (SqlCommand cmd = new SqlCommand("SELECT @@SERVERNAME AS [Server], DB_NAME() AS DbName", cn)) 
     { 
      cn.Open(); 
      using (SqlDataReader reader = cmd.ExecuteReader()) 
      { 
       reader.Read(); 
       server = reader.GetString(0); 
       dbName = reader.GetString(1); 
      } 
     } 
     methodCaller.BeginInvoke(data.Value, server, dbName, new AsyncCallback(Callback), null); 
     //methodCaller.BeginInvoke(data.Value, server, dbName, null, null); 
    } 

    private static void ExecuteAsync(string data, string server, string dbName) 
    { 
     string connectionString = string.Format("Data Source={0};Initial Catalog={1};Integrated Security=SSPI", server, dbName); 
     using (SqlConnection cn = new SqlConnection(connectionString)) 
     using (SqlCommand cmd = new SqlCommand("SyncProcedure", cn)) 
     { 
      cmd.CommandType = CommandType.StoredProcedure; 
      cmd.Parameters.Add("@data", SqlDbType.Xml).Value = data; 
      cn.Open(); 
      cmd.ExecuteNonQuery(); 
     } 
    } 

    private static void Callback(IAsyncResult ar) 
    { 
     AsyncResult result = (AsyncResult)ar; 
     AsyncMethodCaller caller = (AsyncMethodCaller)result.AsyncDelegate; 
     try 
     { 
      caller.EndInvoke(ar); 
     } 
     catch (Exception ex) 
     { 
      // handle the exception 
      //Debug.WriteLine(ex.ToString()); 
     } 
    } 
} 

Nó sử dụng các đại biểu không đồng bộ để gọi SyncProcedure:

CREATE PROCEDURE SyncProcedure(@data xml) 
AS 
    INSERT INTO T(Data) VALUES (@data) 

Ví dụ về gọi AsyncProcedure:

EXEC dbo.AsyncProcedure N'<doc><id>1</id></doc>' 

Unfortunatelly, hội đồng yêu cầu sự cho phép của UNSAFE.

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