* 转载请注明, 有错误还望指正
先说下表结构上的锁类型:
在建表时可以选择三种表的类型:
APL( Allpages locking ): 锁数据页和索引页
DPL( Datapages locking ): 锁数据页
DRL( Datarows locking ): 锁数据这一行
Sybase创建时可以改页大小,之前我们一直是用2K,最近升级到16K,由于大多数表是APL结构,在升级后死锁的数量明显增加。Sybase文档有句话可以借鉴一下:
In many cases, the concurrency problems that result
from allpages locking arise from the index page locks, rather than the locks on
the data pages themselves. Data pages have longer rows than indexes, and often
have a small number of rows per page. If index keys are short, an index page
can store between 100 and 200 keys. An exclusive lock on an index page can
block other users who need to access any of the rows referenced by the index
page, a far greater number of rows than on a locked data page.
意思是说,在索引页上发生的冲突要多于数据页引起的冲突。而16K的server索引页更大,互锁的几率就更大。
想说下怎么测试可以看出锁没锁,还是先把页上的锁介绍一下:
Shared locks (共享锁) 读某数据的时候会加一个这个锁,读取后释放。共享锁可以叠加,就是说一个在读的时候另一个也可以读,不冲突。但是读的时候如果要加排他锁则不行。
Exclusive locks(排他锁) 这个就是有修改操作(delete/insert/update)时会加的锁,这个锁加的时候需要满足没有其他锁在占用,而且它占用了之后别的锁不可以再占用,不能叠加。
Update locks(更新锁?) Sybase有这个锁,不知道其他数据库有没有,它的意思是,如果在update/delete语句执行时,在初始化的时候就在页上加一个更新锁,别人还是可以读,直到其它锁释放,这个更新锁就会followed by一个排他锁。(我理解的是升级成一个排他锁)
测试冲突:
开两个连接,
假如有表 t1 ( a int not null primary key) lock allpages,
有数据:
1
2
3
4
5
connection 1
|
connection 2
|
begin tran
|
|
|
begin tran
|
update t1 set a = a where a = 1
|
|
|
select * from t1 where a = 2
|
会发现connection2的在等待,什么时候返回结果?等1 submit的时候。哪怕不是搜索同一个数据,也会被锁。
Demand locks(要求锁?):
就是说,假如现在有多个事物同时进行,还是刚才的数据:
(假设这个select耗时很长。。。 1会阻塞2,3,4,5,6。。。)
connection 1
|
connection 2
|
connection 3
|
connection 4
|
connection 5
|
connection 6
|
begin tran
|
begin tran
|
begin tran
|
begin tran
|
begin tran
|
begin tran
|
select a from t1 where a = 2
|
|
|
|
|
|
|
update t1 set a = 100 where a = 2
|
|
|
|
|
|
|
select a from t1 where a = 2
|
|
|
|
|
|
|
select a from t1 where a = 2
|
|
|
|
|
|
|
select a from t1 where a = 2
|
|
|
|
|
|
|
select a from t1 where a = 2
|
connection 2 是一个修改请求,排他锁请求,其他都是共享锁,那数据库会按什么顺序执行呢?
1,3,4,5,2,6
为什么是这个顺序? 在2等待时,3来了,因为共享锁可以叠加,那么就先让3跑了,同理4,5也跑了,那这么跑下去,如果一直有人读,那还写不写了。等5跨越2直接读的时候,2已经被忽略了
三次了,这时2会加一个锁,Demand locks,好了,6不让过了。这个锁的意思就是说可以允许最大的忽略次数为3.
如果是并行的操作(parallel execution),同一个并行操作算一次,分支不重复记录。
Table lock(表锁):
设想一下,如果我们用了DRL,select * from t1,是不是每一行用一个锁?
不是的,sybase有lock promotion限制,当你查询超过某一设置值时所有的你用的行锁就升级成一个表锁了,那就happy了,所有接下来在这表上的操作都阻止了(也不是所有,还是符合共享排他锁那个机制,表锁也分共享排他)。
PS: sp_configure 'number
of locks' 可以查看一共有多少锁
PPS: sp_configure 'row
lock promotion' 可以查看超过多少次的行锁可以升级一个表锁替换
Intend lock(不会翻译了。。。意图锁?):
这个锁很有意思,假如我开一个transaction,我update一条语句,好了,我现在其实是有两个锁,一个是行/页的排他锁,还有一个是这个intend exclusive lock。(这个锁也分共享排他)
什么意思呢这个锁,就是说,如果再有别的transaction,要锁表,那么不行,阻挡了。
很好理解,因为我用了这一行,你要锁表也包括这一行,那肯定不行。
那么就出现了这么一种状况,如果t1表很大,我update 了一行(假如a = 2),好了现在有个排他锁和intend锁在这一行了。
那么我再update/delete 其他行,假如update t1 ... where a > 100,里面有10W行是符合的记录,超过了我们前面提的超过多少个行/页锁就升级成表锁,但是又已经有intend了,不能升级,那怎么办。。。
好吧,sybase用了最简单的方法,你选多少行给你多少锁(DRL),要多少给多少。所以说DRL表过多的话很容易造成out of locks的情况。
Range lock / infinity key locks / next-key locks (不会起名了,自己来吧):
这几个锁呢,其实是为了解决幻读(phantoms)问题的,换言之就是只有isolation level 3才可能出现
在解决幻读问题上,APL和D*L是不一样的,APL很简单,锁index pages就行了。(其实我还不太理解。。)
D*L是这样的,我先把你选取的范围先加一个锁(range lock),如果这表里还有其他数据,没被你选到,那我就加next-key locks,意思就是再来的数据或者更新的数据符合我刚才选取的条件,那么不行,等下;如果你选的range是整个表,没别的数据了,那就加个infinity key locks,就防着insert新值符合你的range就行了。我理解是这样的,那么就是说infinity lock是属于next-key lock的只是更简单而已。
而且 这个range lock,我理解大概是一个概念性东西,实现还是靠排他共享锁。
PS: 幻读是什么? 假如一个表,我把里边数据都删了 delete t1,这时还有一个transaction,insert了一条,当我删完再查一看,咦,还有。。。什么情况。。。或者说我delete t1 where a<5,你update t1 set a = a - 5 where a > 5 and a < 10,我再一看,什么情况。。。老板数据库坏了。。。
To be continued.
阅读(3679) | 评论(0) | 转发(0) |