Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (中文) » SQL Anywhere 服务器 - SQL 的用法 » 创建数据库 » 使用事务和隔离级别 » 锁定的工作方式

 

查询过程中的锁定

SQL Anywhere 在用户输入 SELECT 语句时使用的锁定取决于该事务的隔离级别。无论隔离级别为何,所有 SELECT 语句都会在被引用表上获取模式锁。

以隔离级别 0 执行的 SELECT 语句

以隔离级别 0 执行 SELECT 语句时,不需要任何锁定操作。数据库服务器不对各个事务进行保护以防止其它事务更改数据。程序员或数据库用户在解读这些查询的结果时应考虑到这个限制。

以隔离级别 1 执行的 SELECT 语句

SQL Anywhere 在以隔离级别 1 运行事务时使用的锁不比以隔离级别 0 运行时的多很多。数据库服务器只以两种方式修改其操作。

操作中的第一个区别与获取锁定无关,而与是否遵从这些锁定有关。处于隔离级别 0 时,事务可以读取任意行,即使其它事务已在该行获取了写锁定。相反,处于隔离级别 1 的事务在读取每一行之前必须检查该行是否已被放置了写锁定。它不能读取任何被放置了写锁定的行,因为这样做可能会导致读取脏数据。使用 READPAST 提示允许服务器忽略被放置了写锁定的行,但当事务不再阻塞时,其语义不再与隔离级别 1 的语义相符。请参见FROM 子句中的 READPAST 提示。

操作中的第二个区别影响游标稳定性。游标稳定性是通过在游标的当前行上获取一个短期读锁定来实现的。移动游标时,这个读锁定将被释放。如果游标中包含连接的结果,则可能会影响多行。在这种情况下,数据库服务器将在所有为游标的当前行提供信息的行上获取短期读锁定,并在选择游标的另一行作为当前行后释放这些锁定。

以隔离级别 2 执行的 SELECT 语句

在隔离级别 2,数据库服务器会修改其操作以确保可重复读取语义。如果 SELECT 语句从表中的每一行返回值,那么,数据库服务器将在读取表中的每一行时在该行上获取一个读锁定。如果 SELECT 语句包含 WHERE 子句,或其它会对结果中的行加以限制的条件,那么,数据库服务器将读取每一行,测试该行中的值是否符合条件,如果符合,则在该行上获取一个读锁定。所获取的读锁定为长期读锁定,且会一直保持到通过隐式或显式 COMMIT 或 ROLLBACK 语句完成事务为止。与隔离级别 1 相同,隔离级别 2 也确保游标稳定性,且不允许脏读。

以隔离级别 3 执行的 SELECT 语句

以隔离级别 3 工作时,数据库服务器必须确保所有事务调度均可序列化。特别是,除达到隔离级别 2 的要求外,它必须防止幻像行,以保证在所有情况下重新执行同一语句都返回相同的结果。

为达到这个要求,数据库服务器使用了读锁定和幻像锁。以隔离级别 3 执行 SELECT 语句时,数据库服务器会在结果集计算期间处理的每一行上获取读锁定。这样做可确保该事务完成前,其它事务无法修改这些行。

此要求与数据库服务器以隔离级别 2 执行的操作相似,但区别在于必须为每个读取的行获取锁定,无论这些行是否满足 SELECT 语句的 WHERE、ON 或 HAVING 子句中的任何谓语。例如,如果您要选择销售部门中所有雇员的名字,无论以隔离级别 2 还是隔离级别 3 执行该事务,服务器都必须锁定所有包含销售人员信息的行。但是,以隔离级别 3 执行时,服务器还必须在每个不属于销售部门的雇员的相应行上获取读锁定。否则,另一个事务可以在第一个事务仍在执行时将另一个雇员转到销售部门。

当必须为每个读取的行获取读锁定时有两种含义:

  • 数据库服务器需要放置的锁数目可能要比隔离级别 2 所需的锁数目要多得多。获取的幻像锁的数目比为扫描而获取的读锁定的数目多一。此加倍的锁定开销增加了请求的执行时间。

  • 为每个读取的行获取读锁定会对同一表的数据库更新操作的并发性造成负面影响。

数据库服务器获取的幻像锁的数目可能会有很大不同,这取决于查询优化程序所选择的执行策略。由于隔离级别 3 可能会对整体系统并发性产生负面影响,SQL Anywhere 查询优化程序将尝试避免以隔离级别 3 进行顺序扫描,但优化程序进行此操作的能力取决于语句中谓语和被引用表上可用的相关索引。

例如,假设您要选择雇员 ID 为 123 的雇员的相关信息。由于 EmployeeID 是雇员表的主键,因此查询优化程序会几乎毫无疑问地选择索引策略(使用主键索引)来高效定位行。此外,其它事务也不可能将另一个雇员的 ID 更改为 123,因为主键值必须是唯一的。服务器只需在包含雇员 123 相关信息的行上获取一个读锁定,即可确保不会将该 ID 编号分配给其他雇员。

相反,如果您要选择销售部门中的所有雇员,数据库服务器则需要获取更多锁定。如果缺少相关索引,则数据库服务器必须读取雇员表中的每一行,并测试每个雇员是否属于销售部门。如果属于这种情况,则必须为表中的每一行获取读锁定和幻像锁。

SELECT 语句和快照隔离

以快照、语句快照或只读语句快照隔离级别执行的 SELECT 语句不获取读锁定。这是因为每个快照事务(或语句)会看到以前某一时间点的数据库已提交状态的快照。特定的时间点由语句使用三个快照隔离级别中的哪个级别确定。读取事务从不阻塞更新事务,同样更新事务也从不阻塞读取程序。因此,快照隔离除了具有明显的一致性优势之外,还具有相当可观的并发性优势。但快照隔离也有一个缺点,可能花费很大的系统开销。这是因为快照隔离要保证一致性,必须为其它并发事务保存、跟踪并(最终)删除被更改的行的副本。