Sql 使用(NOLOCK)提示进行选择时,是否阻止半写值读取?

Sql 使用(NOLOCK)提示进行选择时,是否阻止半写值读取?,sql,mysql,sql-server,database,oracle,Sql,Mysql,Sql Server,Database,Oracle,我认为这是数据库管理系统之间的问题,尽管我用SQLServer术语指定了它 阅读了msdn文档,例如[1],我无法理解: 是否可以使用(NOLOCK)值选择半写的(部分覆盖的)、更新的、删除的、插入的)值,如果不可以,如何防止(半写的)值读取(如果不遵守锁定) 读取半个写入值违反了哪个DBMS原则? 我很难确定其术语(是否一致性、完整性受损)? 对应术语的名称是什么? 更新: 我从这篇文章中删除了关于更新(删除)和(NOLOCK)的问题。 例如,msdn文档[1]和多篇文章指出,SELECT W

我认为这是数据库管理系统之间的问题,尽管我用SQLServer术语指定了它

阅读了msdn文档,例如[1],我无法理解:

是否可以使用(NOLOCK)值选择半写的(部分覆盖的)、更新的、删除的、插入的)值,如果不可以,如何防止(半写的)值读取(如果不遵守锁定)

读取半个写入值违反了哪个DBMS原则?
我很难确定其术语(是否一致性、完整性受损)?
对应术语的名称是什么?

更新:
我从这篇文章中删除了关于更新(删除)和(NOLOCK)的问题。

例如,msdn文档[1]和多篇文章指出,SELECT WITH(NOLOCK)与READUNCOMMITED相同,并且“不会发出共享锁以防止其他事务修改当前事务读取的数据,并且其他事务设置的独占锁不会阻止当前事务读取锁定的数据”

我是否正确理解DBMS确保只能读取完全写入(提交或未提交)的值?
如果没有使用或遵守锁,如何确保安全?
这个问题不是关于哪个事务可以读取什么以及何时读取,而是如何防止读取未完全写入的值

更新2:
由于这个问题开始被否决和关闭,我将关于更新(删除)和(NOLOCK)的问题移至msdn论坛:

我在msdn论坛上也重复了同样的问题:

这造成了完全的混乱。
但是,为什么它(在这里被关闭,因为它不是一个有答案的问题)?
这是一个非常基本的概念,答案很简单,数据库开发人员和DBA必须清楚地理解它

[1] 表提示(Transact-SQL)
SQL Server 2008 R2

Oracle在任何情况下都不允许脏读(即读取另一个会话的未提交值)。它违反了数据库的“隔离”(I-in),并可能为读取操作提供明显的不一致性[例如看到没有父记录的子记录]

有两种机制在起作用。 首先,每个记录都有一个锁字节,指示它当前是否被锁定。字节的值指向块头中的事务,因此会话可以确定锁是自己的还是属于另一个会话。 如果读操作发现字节已设置,则它使用块头中的指针查找块的旧版本。如果它仍然被锁定,它将继续跟随指针,直到到达记录显示为解锁的块版本。然后返回值

同样的机制也用于基于时间的一致性。如果选择在下午3点开始,并在下午3:02找到一个修改的块,则它会按照历史记录返回,以查找3:00时的当前块版本。然后,它可能会发现它想要的记录在下午3:00被锁定[它可能在下午3:01被提交],并且必须进一步返回以查看下午3:00提交的值


另一种保护机制是闩锁。当它读取一个块时,它会在读取期间对其进行锁存。这将防止另一个进程(可能在另一个CPU上运行)在读取期间访问该块(即进程A不能在线程B读取该块的同时设置锁字节-它必须等待读取完成)。这些锁存器是非常低级别的CPU操作,只能保持很短的时间。在单核/cpu盒上,不需要锁存,因为只有一个核,所以一次只能在线程上执行。

Oracle在任何情况下都不允许脏读(即读取另一个会话的未提交值)。它违反了数据库的“隔离”(I-in),并可能为读取操作提供明显的不一致性[例如看到没有父记录的子记录]

有两种机制在起作用。 首先,每个记录都有一个锁字节,指示它当前是否被锁定。字节的值指向块头中的事务,因此会话可以确定锁是自己的还是属于另一个会话。 如果读操作发现字节已设置,则它使用块头中的指针查找块的旧版本。如果它仍然被锁定,它将继续跟随指针,直到到达记录显示为解锁的块版本。然后返回值

同样的机制也用于基于时间的一致性。如果选择在下午3点开始,并在下午3:02找到一个修改的块,则它会按照历史记录返回,以查找3:00时的当前块版本。然后,它可能会发现它想要的记录在下午3:00被锁定[它可能在下午3:01被提交],并且必须进一步返回以查看下午3:00提交的值


另一种保护机制是闩锁。当它读取一个块时,它会在读取期间对其进行锁存。这将防止另一个进程(可能在另一个CPU上运行)在读取期间访问该块(即进程A不能在线程B读取该块的同时设置锁字节-它必须等待读取完成)。这些锁存器是非常低级别的CPU操作,只能保持很短的时间。在单核/cpu盒上,锁存是不必要的,因为只有一个核,所以无论如何只能在线程上执行。

经过一些思考和实验,我相信DBMS es不提供这样的值完整性:

  • 如果我们假设了这种可能性,那么我们立即得出结论,同一交易中的同一交易
    if object_id('Test') IS not NULL
    drop table Test;
    
    CREATE TABLE Test (
      ID int IDENTITY PRIMARY KEY,
      Txt nvarchar(max) NOT NULL
    )
    GO
    -----------
    INSERT INTO Test
    SELECT REPLICATE(CONVERT(nvarchar(max), 
         CHAR(65+ABS(CHECKSUM(NEWID()))%26)),100000)
    GO 10
    ---
    
    UPDATE Test 
    SET Txt=REPLICATE(CONVERT(nvarchar(max),
               CHAR(65+ABS(CHECKSUM(NEWID()))%26)),100000)
    
    GO 1000 
    
    WHILE 1=1 BEGIN
      SELECT Txt FROM Test WITH (NOLOCK) 
      WHERE LEN(REPLACE(Txt,LEFT(Txt,1),''))<>0;
      select 'rowcount inside=',@@rowcount;
      IF @@ROWCOUNT<>0 BREAK
    END
    --for wishing to try it in non-SqlServer DBMS
    -- WITH(NOLOCK) hint is another way as setting READ UNCOMMITTED tx iso level
    --SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;