最近数据库增加了些不可避免的触发器(程序无法修改)。
所以有时并发量高时出现了死锁。我如果直接把数据库隔离等级改为快照,这样做的副作用是什么呢?
请高手指点。

解决方案 »

  1.   

    SQL Server 还支持使用行版本控制的两个事务隔离级别。一个是已提交读隔离的新实现,另一个是新事务隔离级别(快照)。当 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 时,已提交读隔离使用行版本控制提供语句级读取一致性。读取操作只需要 SCH-S 表级别的锁,不需要页锁或行锁。当 READ_COMMITTED_SNAPSHOT 数据库选项设置为 OFF(默认设置)时,已提交读隔离的行为方式与其在早期版本 SQL Server 中行为方式相同。两个实现都满足已提交读隔离的 ANSI 定义。
    快照隔离级别使用行版本控制来提供事务级别的读取一致性。读取操作不获取页锁或行锁,只获取 SCH-S 表锁。读取其他事务修改的行时,读取操作将检索启动事务时存在的行的版本。将 ALLOW_SNAPSHOT_ISOLATION 数据库选项设置为 ON 时,将启用快照隔离。默认情况下,用户数据库的此选项设置为 OFF。
    注意: 
    SQL Server 不支持元数据的版本控制。因此,对于在快照隔离下运行的显式事务中可以执行的 DDL 操作存在限制。在快照隔离下,BEGIN TRANSACTION 语句之后不允许使用任何公共语言运行时 (CLR) DDL 语句或下列 DDL 语句:ALTER TABLE、CREATE INDEX、CREATE XML INDEX、ALTER INDEX、DROP INDEX、DBCC REINDEX、ALTER PARTITION FUNCTION、ALTER PARTITION SCHEME。在隐式事务中使用快照隔离时允许使用这些语句。根据定义,隐式事务为单个语句,这使得它可以强制应用快照隔离的语义,即便使用 DDL 语句也是如此。违反此原则会导致错误 3961:“数据库 '%.*ls' 中的快照隔离事务失败,因为自此事务启动后,该语句所访问的对象已由其他并发事务中的 DDL 语句修改。这是不允许的,因为未对元数据进行版本控制。如果与快照隔离混合,对元数据的并发更新可能导致不一致。” 
      

  2.   

    以上是帮助内容,主要是在所有显式事务中不能出现ddl语句,你需要检查你的程序中是否符合你确定修改这个隔离级别对你减少死锁有帮助吗?触发器引起的死锁往往是由于触发器写法问题。
      

  3.   


    帮忙看看呢。后来加了 修改时间 这个字段,但是不能改程序。
    这是同一个表的2个触发器
    ALTER TRIGGER [dbo].[aaa] ON [dbo].[tb1] 
    FOR UPDATE
    AS
    begin
      UPDATE tb1
      SET ModiTime = GETDATE()
      From Inserted
      WHERE tb1.HR_No = Inserted.HR_No 
            and tb1.Stat_No = Inserted.Stat_No
          UPDATE tb2
        Set Password = Inserted.Password
        From Inserted
        WHERE tb2.HR_No = Inserted.HR_No
              and Inserted.Password <> '' 
              and Inserted.Password is not NULL
    --  end
    end
    ALTER TRIGGER [dbo].[bbb] ON [dbo].[tb1] 
    FOR INSERT
    AS
    begin
      UPDATE tb1
      SET InTime = GETDATE()
      From Inserted
      WHERE tb1.HR_No = Inserted.HR_No 
            and tb1.Stat_No = Inserted.Stat_No
      IF NOT Exists(Select HR.HR_No From tb1 HR, Inserted Where HR.HR_No = Inserted.HR_No)
      begin
        UPDATE tb2
        Set Password = Inserted.Password
        From Inserted
        WHERE tb2.HR_No = Inserted.HR_No
      end
    end
      

  4.   

    这样都会死锁?
    如果HR_No都是索引列,应该很快。功能好像是记录最后更新时间(这个有时间戳吧),同步密码字段到另一个表(这个可以利用视图吧)
      

  5.   

    触发器感觉有点问题,你需要说明下两个表的主键tb1如果主键是HR_No,为什么要加Stat_No 连接
    tb1如果主键是(HR_No,Stat_No),与tb2的连接就不是唯一的了这一句不知道判断什么
      IF NOT Exists(Select HR.HR_No From tb1 HR, Inserted Where HR.HR_No = Inserted.HR_No) 
      

  6.   

    感谢大神的耐心指导。。tb1的主键是(HR_No,Stat_No)
      

  7.   

    IF NOT Exists(Select HR.HR_No From tb1 HR, Inserted Where HR.HR_No = Inserted.HR_No) 如果更新的TB2的ID 存在于TB1,就更新。
    我是这样理解的,因为我也是维护。。
      

  8.   

    增大对tempdb的压力。不同的事物版本都会保留在tempdb。
      

  9.   

    insert触发器里又套有update, 引发update触发器。然后两个触发器又都去更改tb2的密码。bbb触发器里的udpate password纯多余。但愿能明白我说的什么drop table ccnt,ctst
    go
    create table ccnt(n int)
    go
    create table ctst(id int, x int)
    goinsert ccnt select 0
    insert ctst select 1,1
    go
    select * from ccnt
    select * from ctst
    gocreate trigger tr on ctst for update
    as 
    update ctst set x=x+1
    update ccnt set n=n+1
    go
    create trigger tr1 on ctst for insert
    as
    update ctst set x=x-2
    update ccnt set n=n+1
    go
    insert ctst select 2,20select * from ctst
    select * from ccnt
      

  10.   

    fcuandy确实。。我逻辑能力真差啊,这都看了半天没看出来
      

  11.   

    自己经常遇到,通常是DBA搞定,哈哈,水平还是不行呀
      

  12.   

    在tb1上建立索引(HR_No,Stat_No) 看行不行呢?