2015-02-07 34 views
1

在连接到2014 DB的SQLServer 2014 Management Studio中打开2个窗口。SQL Server锁定机制刺激

在第一窗口:

SELECT * FROM categorytypes WHERE id = 12 

输出:

ID DESCRIPTION ORDER 
--------------------- 
12 Electronics 20 

然后:

begin tran 
UPDATE CategoryTypes SET [order] = 20 WHERE id = 12 

现在转到其它窗口(Ctrl + N键):

SELECT * FROM CategoryTypes 

该查询将无限期执行,直到第一个窗口传输提交或回滚。这很好,因为ID = 12行被锁定。

SELECT * FROM CategoryTypes WHERE ID <> 12 

工作正常。

SELECT * FROM CategoryTypes WHERE Description = 'MEN' 

这是问题,为什么这个查询应该无限期地执行地狱,我们知道ID = 12的描述“电子”。

在一个大型应用程序中,在同一张表上同时执行巨大的DML过程和选择操作时,这种锁定机制不会允许在不同的记录集上同时执行这两件事。

在Oracle这种用例的作品中,只要锁定(脏行)不是结果集的一部分。

伙计们,有没有什么办法可以避免这种Oracle锁定机制?我不想使用NOLOCK,或将我的交易设置为READ UNCOMMITTED

谢谢。

+0

你有机会在这里了解锁。看看sys.dm_tran_locks,看看你的更新事务处理了什么锁,以及select所要求的锁。您可能想要加入sys.dm_tran_session_transactions以将其关联到session_id。 – 2015-02-07 05:43:17

+0

锁定在行上不起作用。它适用于索引记录。根据您的访问路径,锁可能会碰撞或不碰撞。 – usr 2015-02-07 10:12:29

回答

4

在SQL Server中,默认行为是在默认的READ_COMMITTED隔离级别使用锁定。通过这种默认锁定行为,具有有用的索引特别重要,以便仅触摸所需的数据。例如,如果您1)在描述中具有索引,并且2)在查询计划中使用该索引来查找所需的行,则不会阻止在WHERE子句中使用描述的查询。如果没有Description的索引,将导致全表扫描,并且查询在遇到未提交的更改时将被阻止。

如果您想避免锁定,使读者不会阻止编写者,反之亦然,您可以打开READ_COMMITTED_SNAPSHOT数据库选项。然后SQL Server将使用行版本控制而不是锁定来确保只返回提交的数据。

与其他使用行版本控制的DBMS产品一样,READ_COMMITTED_SNAPSHOT的开销比内存中的锁定还要高。 SQL Server每行添加14个字节的额外存储,并且更多地为行版本存储使用tempdb。这些开销成本是否合理取决于工作负载所带来的并发优势。