SQL Server查询返回多行

时间:2010-02-15 16:21:16

标签: sql-server ssis

我目前正在开发一个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

2 个答案:

答案 0 :(得分:1)

NOLOCK提示导致脏读异常,其中一个异常是重复读取。如果更新更改了查询扫描的索引中行的位置,则此类读取很常见:

  • 表示表中有2行,带有ID键,键值为1和2的行
  • 一个请求(T1)运行UPDATE表SET key = 3 WHERE key = 1;
  • 第二个请求(T2)运行SELECT ... FROM table WITH(NOLOCK);
  • T1使用键值1
  • 锁定行
  • T2忽略T1已锁定并读取键值为1的行
  • T2继续并读取具有键值2的行
  • T1更新该行,并将该行移入索引int键值3的新位置
  • T2继续扫描并读取键值为3的行

所以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>

其他重要信息是发现交易使用的锁类型,以便您可以进行相应的计划。