我目前正在开发一个SSIS包,它将表从一个数据库中提取到另一个数据库。两个数据库中的表使用与主键相同的列。我提取数据的select语句是一个简单的select语句。当我运行包时,我收到一个错误,那里有重复的主键值。
我查看了我的select语句并验证了我的select语句没有返回重复的行。因此,为了测试这一点,我从表中删除了主要密钥,我将数据插入到SSIS包中。运行后,我查看了表格,看看哪些行是重复的。我发现的是在提取运行的地方进行编辑的行被复制的地方,编辑前有记录,编辑后有记录。我可以很容易地说出这一点,因为该表有一个最后修改的字段,每次更新记录时都会更新。
我在我的select语句中添加了一个NOLOCK提示,它停止返回重复的行。
所以我的问题是为什么?我原本期望带有NOLOCK表提示的select语句有更高的机会返回重复行,因为它没有使用锁定,并且没有NOLOCK提示的select语句应该使用锁定以确保它不会返回重复行。
这是我用来选择数据的select语句。我确实验证了连接没有导致它重复行:
SELECT pe.enc_id,
pe.enc_nbr,
pe.billable_ind,
pe.clinical_ind AS clinical_ind,
pe.budget_ind,
pe.print_stmt_ind,
pe.send_coll_letter_ind,
pe.outsource_exempt_ind,
cb.First_name + ' ' + cb.last_name AS CreatedBy,
pe.create_timestamp AS create_timestamp,
mb.first_name + ' ' + mb.last_name AS ModifiedBy,
pe.modify_timestamp AS modify_timestamp
FROM patient_encounter pe WITH(NOLOCK)
LEFT OUTER JOIN user_mstr cb WITH(NOLOCK) ON
pe.created_by = cb.user_id
LEFT OUTER JOIN user_mstr mb WITH(NOLOCK) ON
pe.modified_by = mb.user_id
答案 0 :(得分:1)
NOLOCK提示导致脏读异常,其中一个异常是重复读取。如果更新更改了查询扫描的索引中行的位置,则此类读取很常见:
所以SELECT读取了两次,一次是键值1,一次是键值3.这只是一个简单的例子。实际上,更复杂的查询可以运行复杂的计划并使用其他索引,所有这些都会受到这种异常的影响。
简而言之:NOLOCK提示是邪恶的。如果您想避免争用,请使用snapshot isolation。
答案 1 :(得分:0)
WITH NOLOCK提示只是告诉数据库服务器忽略锁定,只是从数据库中选择当前值 - 因此它只是在它到达该行时选择所有当前行值。
请注意,您不会在正在更新的行的新表中获得更新。
如果没有看到你的SQL,我会猜测它的构造方式,它抓住当前行,等待锁定清除,然后选择新行。
锁定整个表格可以防止更改/重复,但是在进行选择时,您可能会将所有人锁定在桌面之外。
编辑: 仅供参考的替代方案:使用由其他进程锁定的READPAST-Rows并跳过 桌面级别的TABLOCK-Lock当然会阻止其他进程,可能不需要。
注意:在事务写入期间,UPDLOCK将转换为XLOCK。
提示有两个类别:粒度和隔离级别。粒度包括PAGLOCK,NOLOCK,ROWLOCK和TABLOCK。隔离级别提示包括HOLDLOCK,NOLOCK,READCOMMITTED,REPEATABLEREAD和SERIALIZABLE。每组最多可使用一个。
EDIT2:仅为完整性:READCOMMITTED-只读已提交事务的数据。这是默认行为。
EDIT3:更多信息:NOLOCK将读取行,但是如果在事务中发生ROLLBACK可能会影响所选集合的准确性,则可能会读取将会更改的“脏”数据或具有不存在的数据。 / p>
其他重要信息是发现交易使用的锁类型,以便您可以进行相应的计划。