Asynchronous Triggers in SQL Server 2005/2008

后端 未结 10 1010
-上瘾入骨i
-上瘾入骨i 2020-12-08 09:51

I have triggers that manipulate and insert a lot of data into a Change tracking table for audit purposes on every insert, update and delete.

This t

相关标签:
10条回答
  • 2020-12-08 10:26

    From sql server 2008 you can use CDC feature for automatically logging changes, which is purely asynchronous. Find more details in here

    0 讨论(0)
  • 2020-12-08 10:27

    I suspect that your trigger is of of these generic csv/text generating triggers designed to log all changes for all table in one place. Good in theory (perhaps...), but difficult to maintain and use in practice.

    If you could run asynchronously (which would still require storing data somewhere for logging again later), then you are not auditing and neither do have history to use.

    Perhaps you could look at the trigger execution plan and see what bit is taking the longest?

    Can you change how you audit, say, to per table? You could split the current log data into the relevant tables.

    0 讨论(0)
  • 2020-12-08 10:28

    To perform asynchronous processing you can use Service Broker, but it isn't the only option, you can also use CLR objects.

    The following is an example of an stored procedure (AsyncProcedure) that asynchronous calls another procedure (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());
            }
        }
    }
    

    It uses asynchronous delegates to call SyncProcedure:

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

    Example of calling AsyncProcedure:

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

    Unfortunatelly, the assembly requires UNSAFE permission.

    0 讨论(0)
  • 2020-12-08 10:31

    There's a basic conflict between "does its job very well" and "unacceptable", obviously.

    It sounds to me that you're trying to use triggers the same way you would use events in an OO procedural application, which IMHO doesn't map.

    I would call any trigger logic that takes 30 seconds - no, more that 0.1 second - as disfunctional. I think you really need to redesign your functionality and do it some other way. I'd say "if you want to make it asynchronous", but I don't think this design makes sense in any form.

    As far as "asynchronous triggers", the basic fundamental conflict is that you could never include such a thing between BEGIN TRAN and COMMIT TRAN statements because you've lost track of whether it succeeded or not.

    0 讨论(0)
提交回复
热议问题