哪个是更快的触发器或存储过程?

时间:2019-04-30 00:48:46

标签: sql-server tsql

我目前在每个表上都有一个触发器来处理历史记录日志。每个表上的触发器都是完全相同的。见下文。

如果我将其移至存储过程,会更快吗?

如果我使用存储过程,触发器是否会释放给用户继续?

create trigger ' + @TABLE_NAME + '_ChangeTracking on ' + @TABLE_NAME + ' for 
insert, update, delete
as
    declare @bit int ,
            @field int ,
            @maxfield int ,
            @char int ,
            @fieldname varchar(128) ,
            @TableName varchar(128) ,
            @PKCols varchar(1000) ,
            @sql nvarchar(max), 
            @Type nvarchar(1) ,
            @PKValueSelect varchar(1000),
            @MasterId nvarchar(max) = ''0''

    select @TableName = ''' + @TABLE_NAME + '''

    if exists(select * from CNF_HIL_Tables where referencetable = @TableName and Active = 1)
    begin
        if exists (select * from inserted)
            if exists (select * from deleted)
                select @Type = ''2''
            else
                select @Type = ''3''
        else
            select @Type = ''1''

        select * into #ins from inserted
        select * into #del from deleted

        select @PKCols = coalesce(@PKCols + '' and'', '' on'') + '' i.'' + c.COLUMN_NAME + '' = d.'' + c.COLUMN_NAME
        from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk 
        inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE c on c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME and c.TABLE_NAME = pk.TABLE_NAME
        where pk.TABLE_NAME = @TableName
          and CONSTRAINT_TYPE = ''PRIMARY KEY''

        select @PKValueSelect = coalesce(@PKValueSelect+''+'','''') + ''convert(varchar(100), coalesce(i.'' + COLUMN_NAME + '',d.'' + COLUMN_NAME + ''))''
        from INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk    
        inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE c on c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME and c.TABLE_NAME = pk.TABLE_NAME  
        where pk.TABLE_NAME = @TableName   
          and CONSTRAINT_TYPE = ''PRIMARY KEY'' 

        select @field = 0, 
               @maxfield = max(ORDINAL_POSITION) 
        from INFORMATION_SCHEMA.COLUMNS 
        where TABLE_NAME = @TableName

        while @field < @maxfield
        begin
            select @field = min(ORDINAL_POSITION) 
            from INFORMATION_SCHEMA.COLUMNS 
            where TABLE_NAME = @TableName 
              and ORDINAL_POSITION > @field

            select @bit = (@field - 1 )% 8 + 1
            select @bit = power(2,@bit - 1)
            select @char = ((@field - 1) / 8) + 1

            if substring(COLUMNS_UPDATED(),@char, 1) & @bit > 0 or @Type in (''1'',''3'')
        begin
            select @fieldname = COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = @TableName and ORDINAL_POSITION = @field

            if exists(select * from CNF_Hil_Columns INNER JOIN CNF_HIL_Tables    ON CNF_HIL_Tables.TablesId = CNF_Hil_Columns.TablesId
                                where CNF_HIL_Tables.referencetable = @TableName  and CNF_Hil_Columns.ColumnName = @fieldname
                                    and CNF_Hil_Columns.Active = 1
                        )
            begin

                if @MasterId = 0
                begin
                    select @sql = ''insert DATA_HIL_Master (OperationType, ReferenceTable, ReferenceId, UserId, WorkstationId, InsDateTime)''
                    select @sql = @sql + '' select '''''' + @Type + ''''''''                                                
                    select @sql = @sql + '', '''''' + @TableName + ''''''''     
                    select @sql = @sql + '','' + @PKValueSelect     
                    select @sql = @sql + '',convert(varchar(1000),i.Last_UserId_Log)''
                    select @sql = @sql + '',convert(varchar(1000),i.Last_WorkstationId_Log)''
                    select @sql = @sql + '',convert(varchar(1000),i.Last_DateTime_Log)''
                    select @sql = @sql + '' from #ins i full outer join #del d''
                    select @sql = @sql + @PKCols 
                    select @sql = @sql + '' SELECT @MasterId = SCOPE_IDENTITY() ''
                    EXECUTE sp_executesql @sql, N''@MasterId nvarchar(max) OUTPUT'', @MasterId OUTPUT
                end

                select @sql = ''insert data_HIL_Detail (MasterId, ColumnName, OriginalValue, ModifiedValue)''
                select @sql = @sql + '' select convert(varchar(1000),'' + @MasterId + '')''
                select @sql = @sql + '','''''' + @fieldname + ''''''''
                select @sql = @sql + '', convert(varchar(1000),d.'' + @fieldname + '')''
                select @sql = @sql + '', convert(varchar(1000),i.'' + @fieldname + '')''
                select @sql = @sql + '' from #ins i full outer join #del d''
                select @sql = @sql + @PKCols

                EXECUTE sp_executesql @sql
            END
        END
    END 
END

2 个答案:

答案 0 :(得分:0)

通常,与触发器或存储过程无关,您都有相同的代码。在触发器中,不能直接调用它,而在存储过程中,则是直接调用。因此,无论您使用触发器还是存储过程,明智的执行都是相同的。第一次调用执行计划时,将对其进行缓存。

在您的情况下,由于您正在专门使用插入的,已删除的表,因此您应该具有不同的存储过程代码来实施审核。或者,您可以考虑使用SQL Server temporal tablesChange Data CaptureSQL Server auditing

但是,使用触发器没有什么缺点。

  • 它可以延长交易时间
  • 难以调试

答案 1 :(得分:0)

我实际上是在寻找这个问题的答案,偶然发现这里。

我找到了许多不同的答案,但是作为一名学生,我目前被告知“存储过程比单个SQL语句运行得更快;这提高了性能”。因此,答案似乎是“是”。

但是,似乎“表现”可能由不同的人有不同的解释。我还不是很有经验,所以我还不太了解所有细微差别。我已经看到一些评论将差异归因于“缓存”,还有一些评论则建议使用存储过程仅仅是因为更好地“控制”了安全性和维护性,而不是任何与性能相关的东西。

在阅读课程资料时,我还遇到了一些可能相关的问题。摘自使用PostgreSQL入门数据库:从新手到专业人士(Stones和Matthew,2005年):

存储过程位于服务器端,而不是客户端,添加到 访问控制。从客户端调用,仅将结果传递给调用方,这减少了网络流量。多个应用程序可以使用一个存储过程,从而标准化处理规则。

所以,也许这就是“性能”的含义。

存储过程似乎也更类似于函数本身,函数是存储在数据库中并由所有其他数据库对象使用的对象。触发器是与运行函数的表关联的对象。

相关问题