对于select语句:
1、当采用表扫描时,会直接锁定page,而不是锁定具体的某条记录,所以会有这些锁:
A、数据库S锁
B、表的IS锁
C、页的S锁
2、当采用索引来查找数据时,会锁定具体的记录,所以会有这些锁:
A、数据库S锁
B、索引中page的IS锁
C、索引中page中的key的S锁
D、表的IS锁
E、页的IS锁
F、RID的S锁
3、对于读过的页面,会加一个IS锁。
对于使用的索引,会对key加上S锁,对索引key所在的页面会加上IS锁。
在查询过程中,会对每一条读到的记录或key加上S锁。
如果记录不是我们要查找的,那么就会释放S锁,如果记录要返回,根据隔离级别,如果是read committed,那么会释放,否则就不会释放。
对于update语句:
1、当采用表扫描时,会直接锁定page,而不是锁定具体的某条记录,所以会有这些锁:
A、数据库S锁
B、表的IX锁
C、页的U锁 或者是X锁,两者的区别在于,由于update语句也是要先找到数据,才能进行修改,所以在查数据时,会对页加上IU锁,然后在继续查看页中的记录时,会先对记录加上U锁,如果发现这条记录,不是需要更新的,那么会立即释放U锁,如果发现这条记录就是要更新的,那么就会加上X锁,然后update这条记录,然后查看下一条记录。
2、当采用索引来查找数据时,会索引具体的记录,所以会有这些锁:
A、数据库S锁
B、索引中page的IU锁
C、索引中page中的key的U锁,也就是不希望别的会话来修改这条记录的key字段,比如现在有2个会话,1个要修改第10条记录的name字段,另一个是要修改第10条记录的key字段,显然,在一个会话修改同一条记录的name字段时,肯定会阻塞住另一个会话修改key字段。也就是说,对同一条记录的不同字段,肯定是不能同时修改的,总是有个先后,否则数据就不一致了。
D、表的IX锁
E、页的IU锁 或者是IX锁,这个区别和上面是一样的,查询时用的是IU锁,当发现这个页内部有需要修改的记录时,会转化为IX锁。
F、RID的X锁
3、对每一个使用的索引,会对key加上U锁,对索引key所在的页面会加上IU锁。
由于update也需要先找到记录,然后才能更新,所以,在扫描过程中,对要扫描的记录所在的页,加上IU锁,对页中的记录加上U锁,如果这些记录要修改,那么会升级为X锁,页面会升级为IX锁。如果这个记录不需要更新,那么会释放U锁,如果整个页面都没有要修改的记录,那么也会释放IU锁。
另外,使用到要修改列的索引越多,那么锁也会越多。比如现在要修改name字段的值,而包含name字段的索引有2个,那么在修改name时,也需要锁定这2个索引的页面和key,所以会先修改表中name字段的值,然后再修改涉及到name字段的2个索引的key值,这个修改操作是先删除,然后再插入key值,比如,要update 3条记录,那么最后修改索引时,会申请6个key 的X锁,3个是要删除的,3个是要插入的。
不过需要特别注意的是,update语句和select 语句的区别在于,update语句获取的锁,直到事务结束,才会释放。
对于Insert 语句:
A、数据库S锁
B、表的IX锁
C、页的IX锁,对于要新插入数据的页,也会有一个IX锁。
D、RID,对要新插入的数据,会申请一个X锁。
E、如果表中有多个索引,那么每个索引上都要插入一条新的数据,要插入数据所在页上,会有一个IX锁。
F、要插入索引中的key,也会有一个X锁。
注意:IS、IU(暂时没发现在表级别上有这个锁)、IX这3个意向锁,都是在表级别、页级别的,而S、U(暂时没没发现在表级别有这个锁)、X 可以在多个级别上。
SQL Server中DML语句要申请的锁