首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >触发器和存储过程哪个更快?

触发器和存储过程哪个更快?
EN

Stack Overflow用户
提问于 2019-04-30 08:48:46
回答 2查看 452关注 0票数 0

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

如果我把它移到一个存储过程中,它会更快吗?

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

代码语言:javascript
复制
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
EN

回答 2

Stack Overflow用户

发布于 2019-04-30 12:55:46

通常,不管是触发器还是存储过程,您都会得到相同的代码。在触发器中,你不能直接调用它,而在存储过程中,你直接调用它。因此,无论您使用触发器还是存储过程,在执行方面都是一样的。第一次调用它时,将缓存执行计划。

在您的例子中,由于您专门使用插入的、删除的表,因此您应该使用不同的存储过程代码来实现审计。或者,您可以考虑使用SQL Server temporal tablesChange Data CaptureSQL Server auditing

但是,使用触发器的缺点很少。

它可以使事务调试longer

  • Difficult to
票数 0
EN

Stack Overflow用户

发布于 2020-12-11 12:43:13

我实际上是在寻找这个问题的答案,结果在这里跌跌撞撞。

我已经找到了很多不同的答案,但作为一名学生,我现在被告知“存储过程比单个SQL语句运行得更快;这提高了性能。”所以,答案似乎是肯定的。

然而,不同的人可能会对“性能”有不同的解释。我还不是很有经验,所以我还不能真正理解所有的细微差别。我看到一些评论将这种差异归因于“缓存”,而另一些评论建议使用存储过程只是因为更好的“控制”安全性和维护性,而不是任何与性能相关的东西。

在阅读我的课程材料时,我也发现了一些可能相关的东西。这是从PostgreSQL数据库开始:从新手到专业人员(Stones and Matthew,2005):

存储过程驻留在服务器端,而不是客户端,增加了访问控制。从客户端调用,只将结果传递给调用者,这减少了网络流量。多个应用程序可以使用单个存储过程,从而标准化处理规则。

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55912545

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档