事务隔离级别脏读幻读_脏读和未提交读隔离级别

事务隔离级别脏读幻读

In this article, we will discuss the Dirty Read concurrency issue and also learn the details of the Read Uncommitted Isolation Level.

在本文中,我们将讨论“ 脏读”并发问题,并了解“ 读未提交的隔离级别”的详细信息。

A transaction is the smallest working unit that performs the CRUD (Create, Read, Update, and Delete) actions in the relational database systems. Relevant to this matter, database transactions must have some characteristics to provide database consistency. The following four features constitute the major principles of the transactions to ensure the validity of data stored by database systems. These are;

事务是在关系数据库系统中执行CRUD(创建,读取,更新和删除)操作的最小工作单元。 与此相关的是,数据库事务必须具有某些特性以提供数据库一致性。 以下四个功能构成了事务的主要原理,以确保数据库系统存储的数据的有效性。 这些是;

  • Atomicity 一个 tomicity
  • Consistency çonsistency
  • Isolation 我这样
  • Durability d urability

These four properties are also known as ACID principles. Let’s briefly explain these four principles.

这四个属性也称为ACID原理。 让我们简要解释这四个原则。

原子性 (Atomicity )

This property is also known as all or nothing principle. According to this property, a transaction can not be completed partially, so if a transaction gets an error at any point of the transaction, the entire transaction should be aborted and rollbacked. Or, all the actions contained by a transaction must be completed successfully.

此属性也称为“全部或全部”原则。 根据此属性,不能部分完成事务,因此,如果事务在事务的任何点出现错误,则应中止并回滚整个事务。 或者,必须成功完成事务包含的所有操作。

一致性 (Consistency )

According to this property, the saved data must not damage data integrity. This means that the modified data must provide the constraints and other requirements that are defined in the database.

根据此属性,保存的数据不得破坏数据完整性。 这意味着修改后的数据必须提供数据库中定义的约束和其他要求。

耐用性 (Durability)

According to this property, the committed will not be lost even with the system or power failure.

根据此属性,即使系统或电源出现故障,提交的内容也不会丢失。

隔离 (Isolation )

The database transactions must complete their tasks independently from the other transactions. This property enables us to execute the transactions concurrently on the database systems. So, the data changes which are made up by the transactions are not visible until the transactions complete (committed) their actions. The SQL standard describes three read phenomena, and they can be experienced when more than one transaction tries to read and write to the same resources.

数据库事务必须独立于其他事务完成其任务。 此属性使我们能够在数据库系统上并发执行事务。 因此,在事务完成(提交)其操作之前,由事务构成的数据更改是不可见的。 SQL标准描述了三种读取现象,当多个事务尝试读取和写入相同的资源时可能会遇到这种现象。

  • Dirty-reads

    脏读
  • Non-repeatable reads

    不可重复读
  • Phantom reads

    幻影阅读

什么是脏读? (What is Dirty Read?)

The simplest explanation of the dirty read is the state of reading uncommitted data. In this circumstance, we are not sure about the consistency of the data that is read because we don’t know the result of the open transaction(s). After reading the uncommitted data, the open transaction can be completed with rollback. On the other hand, the open transaction can complete its actions successfully. The data that is read in this ambiguous way is defined as dirty data. Now we will explain this issue with a scenario:

脏读取的最简单解释是读取未提交数据的状态。 在这种情况下,我们不确定所读取数据的一致性,因为我们不知道未完成交易的结果。 读取未提交的数据后,可以通过回滚完成未完成的事务。 另一方面,未清事务可以成功完成其操作。 以这种歧义方式读取的数据被定义为脏数据。 现在,我们将用一个场景来解释这个问题:

Assuming we have a table as shown below that stores the bank account details of the clients.

假设我们有一个下表,该表存储了客户的银行帐户详细信息。

AccountNumber

ClientName

Balance

7Y290394

Betty H. Bonds

$78.00

账号

客户名称

平衡

7Y290394

贝蒂·H·邦兹

$ 78.00

In this scenario, Betty has $78.00 in her bank account, and the automatic payment system withdraws $45 from Betty’s account for the electric bill. At that time, Betty wants to check her bank account on the ATM, and she notices $33 in her bank account. However, if the electric bill payment transaction is rollbacked for any reason, the bank account balance will be turned to $78.00 again, so the data read by Betty is dirty data. In this case, Betty will be confused. The following diagram illustrates this dirty read scenario in a clearer manner.

在这种情况下,Betty的银行帐户有$ 78.00,自动付款系统会从Betty的帐户中提取$ 45的电费。 当时,贝蒂想在自动柜员机上检查她的银行帐户,她发现自己的银行帐户中有33美元。 但是,如果由于任何原因而回扣了电费支付交易,则银行帐户余额将再次变为$ 78.00,因此Betty读取的数据是肮脏的数据。 在这种情况下,贝蒂会感到困惑。 下图以更清晰的方式说明了这种脏读情况。

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第1张图片

Now we will realize this scenario in practice with SQL Server. Firstly we will create the BankDetailTbl table that stores the bank account details of the clients.

现在,我们将在SQL Server的实践中实现这种情况。 首先,我们将创建BankDetailTbl表,该表存储客户的银行帐户详细信息。

CREATE TABLE BankDetailTbl
(
  Id            INT
  PRIMARY KEY IDENTITY(1, 1), 
  AccountNumber VARCHAR(40), 
  ClientName    VARCHAR(100), 
  Balance       MONEY);

As a second step, we will insert a sample row to it.

第二步,我们将在其中插入一个示例行。

INSERT INTO BankDetailTbl
VALUES
('7Y290394', 'Betty H. Bonds', '78');

Now we will execute the following queries, the Query-1 updates the balance value of the particular bank account, and then it will wait 20 seconds and rollback the data modification. At this moment, we will immediately execute the Query-2, and this query reads the modified but uncommitted data.

现在,我们将执行以下查询,Query-1更新特定银行帐户的余额值,然后将等待20秒并回滚数据修改。 此时,我们将立即执行Query-2,此查询将读取已修改但未提交的数据。

Query-1:

查询1:

BEGIN TRAN;
UPDATE BankDetailTbl
SET 
    Balance=Balance-45
WHERE AccountNumber = '7Y290394';
WAITFOR DELAY '00:00:20';
ROLLBACK TRAN;
 
SELECT *
FROM BankDetailTbl
WHERE AccountNumber = '7Y290394';

Query-2:

查询2:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRAN;
SELECT *
FROM BankDetailTbl
WHERE AccountNumber = '7Y290394';
COMMIT TRAN;

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第2张图片

As a result, the data read by Query-2 was dirty because the data was returned to its first state because of the rollback process.

结果,由于回滚过程使数据返回到其第一状态,因此Query-2读取的数据很脏。

读未提交与读提交隔离级别 (The Read Uncommitted vs Read Committed Isolation Level)

As we explained, a transaction must be isolated from other transactions according to the isolation property of the ACID transactions. In this context, isolation levels specify the isolation strategy of a transaction from the other transactions.

正如我们所解释的,必须根据ACID事务的隔离属性将一个事务与其他事务隔离。 在这种情况下, 隔离级别指定一个事务与其他事务的隔离策略。

什么是排他锁? (What is Exclusive Lock?)

By default, SQL Server sets an exclusive lock for data that is being modified to ensure data consistency until the transaction is complete. So, it isolates the modified data from the other transaction.

默认情况下,SQL Server为正在修改的数据设置排他锁,以确保数据一致性,直到事务完成为止。 因此,它将修改后的数据与其他事务隔离。

Read uncommitted is the weakest isolation level because it can read the data which are acquired exclusive lock to the resources by the other transactions. So, it might help to avoid locks and deadlock problems for the data reading operations. On the other hand, Read Committed can not read the resource that acquires an exclusive lock, and this is the default level of the SQL Server.

读取未提交是最弱的隔离级别,因为它可以读取通过其他事务获得的对资源的独占锁定的数据。 因此,这可能有助于避免数据读取操作的锁定和死锁问题。 另一方面, Read Committed无法读取获得排他锁的资源,这是SQL Server的默认级别。

Now we will work on an example of this difference to figure this out. With the help of the Query-3, we will change the ClientName column value of a client. During this time, Query-4 tries to read the same client details, but Query-4 could not be read the data until the Query-3 completes the update action. At first, we will execute the Query-3.

现在,我们将研究这种差异的一个例子,以解决这一问题。 借助Query-3,我们将更改客户端的ClientName列值。 在此期间,Query-4尝试读取相同的客户端详细信息,但是直到Query-3完成更新操作之前,Query-4才能读取数据。 首先,我们将执行Query-3。

Query-3:

查询3:

BEGIN TRAN;
UPDATE BankDetailTbl
SET 
    ClientName='Doris P. Barnum'
WHERE AccountNumber = '7Y290394';
WAITFOR DELAY '00:00:50'
ROLLBACK TRAN

After executing the Query-3, we are executing the Query-4 immediately on another query window at this moment.

执行完Query-3之后,我们现在正在另一个查询窗口上立即执行Query-4。

Query-4:

查询4:

DECLARE @TimeDiff AS INT
DECLARE @BegTime AS DATETIME
DECLARE @EndTime AS DATETIME
BEGIN TRAN
SET @BegTime = GETDATE()
SELECT ClientName FROM BankDetailTbl 
WHERE AccountNumber = '7Y290394';
SET @EndTime = GETDATE()
SET @TimeDiff = DATEDIFF(SECOND,@EndTime,@BegTime)
SELECT @TimeDiff AS QueryCompletionTime
COMMIT TRAN

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第3张图片

In Query-4, we have measured the query completion time, and the @TimeDiff variable indicates this measured time. As we have seen, Query-4 has completed on 49 seconds because it has waited for the completion of the Query-3 because the Read Committed level does not allow dirty reads. Now we will change this level to Read Uncommitted for Query-4. SET TRANSACTION ISOLATION LEVEL statement helps to explicitly change the isolation level for a transaction. We will execute the Query-3 and Query-4 at the same order and will observe the result.

在查询4中, 我们 已测量查询完成时间, @ TimeDiff变量指示此测量时间。 正如我们所看到的,Query-4之所以完成了49秒,是因为它等待Query-3的完成,因为Read Committed级别不允许脏读。 现在,我们将把此级别更改为对Query-4的读取未提交SET TRANSACTION ISOLATION LEVEL语句有助于显式更改事务的隔离级别。 我们将以相同的顺序执行Query-3和Query-4,并将观察结果。

Query-3:

查询3:

BEGIN TRAN;
UPDATE BankDetailTbl
SET 
    ClientName='Doris P. Barnum'
WHERE AccountNumber = '7Y290394';
WAITFOR DELAY '00:00:50'
ROLLBACK TRAN

Query-4:

查询4:

DECLARE @TimeDiff AS INT
DECLARE @BegTime AS DATETIME
DECLARE @EndTime AS DATETIME
BEGIN TRAN
SET @BegTime = GETDATE()
SELECT ClientName FROM BankDetailTbl 
WHERE AccountNumber = '7Y290394';
SET @EndTime = GETDATE()
SET @TimeDiff = DATEDIFF(SECOND,@EndTime,@BegTime)
SELECT @TimeDiff AS QueryCompletionTime
COMMIT TRAN

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第4张图片

As we can see, the Query-4 did not wait for the completion of the Query-3 and completed as soon as possible.

如我们所见,Query-4没有等待Query-3的完成,而是尽快完成。

分配顺序扫描和读取未提交的隔离级别 (Allocation Order Scans and Read Uncommitted Isolation Level)

In this section, we will discuss an internal secret of the query execution mechanism of the SQL Server. At first, we will execute the following query in the AdventureWorks2017 sample database.

在本节中,我们将讨论SQL Server查询执行机制的内部秘密。 首先,我们将在AdventureWorks 2017示例数据库中执行以下查询。

CHECKPOINT;
DBCC DROPCLEANBUFFERS;
GO
BEGIN TRAN
SELECT WorkOrderID, 
       StartDate, 
       EndDate
FROM Production.WorkOrder; 
COMMIT TRAN

These query results are sorted by the WorkOrderId column.

这些查询结果按WorkOrderId列排序。

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第5张图片

Now, we will change the isolation and execute the same query on another query window. However, the result is slightly different than we expected because of the WorkOrderID column sort.

现在,我们将更改隔离,并在另一个查询窗口上执行相同的查询。 但是,由于WorkOrderID列的排序,结果与我们预期的略有不同。

CHECKPOINT;
DBCC DROPCLEANBUFFERS;
GO
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRAN
SELECT WorkOrderID, 
       StartDate, 
       EndDate
FROM Production.WorkOrder; 
COMMIT TRAN

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第6张图片

When we compare the execution plans of these two queries, we could not find any logical difference between them.

当我们比较这两个查询的执行计划时,我们找不到它们之间的任何逻辑差异。

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第7张图片

In the execution plan, if we look at the clustered index scan operator Ordered attribute, it shows the “False” value.

在执行计划中,如果我们查看聚簇索引扫描运算符Ordered属性,它将显示“ False”值。

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第8张图片

In this case, the storage engine has two options for accessing the data. The first one is an index order scan that uses the B-tree index structure. The second option is an allocation order scan, and it uses the Index Allocation Map (IAM) and performs the scan in the physical allocation order.

在这种情况下,存储引擎有两个用于访问数据的选项。 第一个是使用B树索引结构的索引顺序扫描 。 第二个选项是分配顺序扫描,它使用索引分配图(IAM)并按照物理分配顺序执行扫描。

Allocation order scans can be considered by the database engine when the following reason meets because we don’t care about the data read data consistency.

当满足以下原因时,数据库引擎可以考虑分配顺序扫描,因为我们不在乎数据读取数据的一致性。

  • The index size is greater than 64 pages

    索引大小大于64页
  • NOLOCK hint NOLOCK提示运行
  • The Ordered attribute of the Index Scan operator is false

    索引扫描运算符的Ordered属性为false

Tip: Allocation order scans can be performed when we use the TABLOCK hint in a query.

提示:当我们在查询中使用TABLOCK提示时,可以执行分配顺序扫描。

CHECKPOINT;
DBCC DROPCLEANBUFFERS;
GO
BEGIN TRAN
SELECT WorkOrderID, 
       StartDate, 
       EndDate
FROM Production.WorkOrder  WITH(TABLOCK); 
COMMIT TRAN

事务隔离级别脏读幻读_脏读和未提交读隔离级别_第9张图片

结论 (Conclusion)

In this article, we discussed the dirty read issue and also explained the Read Uncommitted Isolation Level differences. This level has its own characteristics, so when you decide to use it, we need to take into account lock, data consistency, and other issues. At the same time, we also explored the allocation order scan data access method and details.

在本文中,我们讨论了脏读问题,并解释了读未提交隔离级别的差异。 此级别具有其自身的特征,因此当您决定使用它时,我们需要考虑锁定,数据一致性和其他问题。 同时,我们还探讨了分配顺序扫描数据的访问方法和细节。

翻译自: https://www.sqlshack.com/dirty-reads-and-the-read-uncommitted-isolation-level/

事务隔离级别脏读幻读

你可能感兴趣的:(事务隔离级别脏读幻读_脏读和未提交读隔离级别)