tan*_*ens 76 sql t-sql sql-server sql-server-2005 read-committed-snapshot
我使用的是隔离级别的Microsoft SQL Server 2005数据库READ_COMMITTED
和READ_COMMITTED_SNAPSHOT=ON
.
现在我想用:
SELECT * FROM <tablename> FOR UPDATE
Run Code Online (Sandbox Code Playgroud)
...以便在尝试访问同一行"FOR UPDATE"时阻止其他数据库连接.
我试过了:
SELECT * FROM <tablename> WITH (updlock) WHERE id=1
Run Code Online (Sandbox Code Playgroud)
...但是即使选择"1"以外的ID,这也会阻止所有其他连接.
SELECT FOR UPDATE
对于Oracle,DB2,MySql而言,这是正确的提示吗?
编辑2009-10-03:
这些是创建表和索引的语句:
CREATE TABLE example ( Id BIGINT NOT NULL, TransactionId BIGINT,
Terminal BIGINT, Status SMALLINT );
ALTER TABLE example ADD CONSTRAINT index108 PRIMARY KEY ( Id )
CREATE INDEX I108_FkTerminal ON example ( Terminal )
CREATE INDEX I108_Key ON example ( TransactionId )
Run Code Online (Sandbox Code Playgroud)
很多并行进程都这样做SELECT
:
SELECT * FROM example o WITH (updlock) WHERE o.TransactionId = ?
Run Code Online (Sandbox Code Playgroud)
编辑2009-10-05:
为了更好地概述,我在下表中写下了所有尝试过的解决方案:
mechanism | SELECT on different row blocks | SELECT on same row blocks -----------------------+--------------------------------+-------------------------- ROWLOCK | no | no updlock, rowlock | yes | yes xlock,rowlock | yes | yes repeatableread | no | no DBCC TRACEON (1211,-1) | yes | yes rowlock,xlock,holdlock | yes | yes updlock,holdlock | yes | yes UPDLOCK,READPAST | no | no I'm looking for | no | yes
Ste*_*ger 33
最近我遇到了死锁问题,因为Sql Server会锁定更多必要的(页面).你无法真正做任何反对它.现在我们正在捕捉死锁异常......我希望我有Oracle.
编辑:我们同时使用快照隔离,这解决了很多但不是所有的问题.遗憾的是,为了能够使用快照隔离,数据库服务器必须允许它,这可能会在客户站点上造成不必要的问题.现在我们不仅捕获死锁异常(当然仍然可以发生),而且还捕获快照并发问题以从后台进程重复事务(用户不能重复).但这仍然比以前表现得更好.
小智 19
我有类似的问题,我想只锁定1行.据我所知,使用UPDLOCK
选项,SQLSERVER会锁定它需要读取的所有行以获取行.因此,如果您没有定义索引来直接访问该行,则所有前面的行都将被锁定.在你的例子中:
假设您有一个名为TBL的表,其中包含一个id
字段.你想锁定行id=10
.您需要为字段ID(或您选择的任何其他字段)定义索引:
CREATE INDEX TBLINDEX ON TBL ( id )
Run Code Online (Sandbox Code Playgroud)
然后,您的查询仅锁定您读取的行:
SELECT * FROM TBL WITH (UPDLOCK, INDEX(TBLINDEX)) WHERE id=10.
Run Code Online (Sandbox Code Playgroud)
如果您不使用INDEX(TBLINDEX)选项,SQLSERVER需要从表的开头读取所有行以查找您的行id=10
,因此这些行将被锁定.
完整的答案可以深入研究DBMS的内部.它取决于查询引擎(执行SQL优化器生成的查询计划)的运行方式.
但是,一个可能的解释(适用于某些DBMS的至少某些版本 - 不一定适用于MS SQL Server)是ID列上没有索引,因此任何尝试使用' WHERE id = ?
'进行查询的进程最终都会执行对表进行顺序扫描,顺序扫描会触发您的进程应用的锁.如果DBMS默认应用页面级锁定,也会遇到问题; 锁定一行会锁定整个页面以及该页面上的所有行.
有一些方法你可以揭穿这个麻烦的来源.查看查询计划; 研究指标; 尝试使用ID为1000000而不是1的SELECT,并查看是否仍然阻止了其他进程.
或许使mvcc永久化可以解决它(而不是仅与特定批次相反:SET TRANSACTION ISOLATION LEVEL SNAPSHOT):
ALTER DATABASE yourDbNameHere SET READ_COMMITTED_SNAPSHOT ON;
Run Code Online (Sandbox Code Playgroud)
[编辑:10月14日]
阅读本文后:Oracle中的并发性比SQL Server更好?这个:http://msdn.microsoft.com/en-us/library/ms175095.aspx
当READ_COMMITTED_SNAPSHOT数据库选项设置为ON时,将立即激活用于支持该选项的机制.设置READ_COMMITTED_SNAPSHOT选项时,只允许在数据库中执行ALTER DATABASE命令的连接.ALTER DATABASE完成之前,数据库中必须没有其他打开的连接.数据库不必处于单用户模式.
我得出结论,你需要设置两个标志,以便在给定的数据库上永久激活mssql的MVCC:
ALTER DATABASE yourDbNameHere SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE yourDbNameHere SET READ_COMMITTED_SNAPSHOT ON;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
170301 次 |
最近记录: |