SQL Server误区30日谈-Day26-SQL Server中存在真正的“事务嵌套”

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
日志服务 SLS,月写入数据量 50GB 1个月
简介:
    本系列文章是我在sqlskill.com的PAUL的博客看到的,很多误区都比较具有典型性和代表性,原文来自T-SQL Tuesday #11: Misconceptions about.... EVERYTHING!!,经过我们团队的翻译和整理发布在AgileSharp上。希望对大家有所帮助。

 

误区 #26: SQL Server中存在真正的“事务嵌套”

错误

 

    嵌套事务可不会像其语法表现的那样看起来允许事务嵌套。我真不知道为什么有人会这样写代码,我唯一能够想到的就是某个哥们对SQL Server社区嗤之以鼻然后写了这样的代码说:“玩玩你们”。

    让我更详细的解释一下,SQL Server允许你在一个事务中开启嵌套另一个事务,SQL Server允许你提交这个嵌套事务,也允许你回滚这个事务。

    但是,嵌套事务并不是真正的“嵌套”,对于嵌套事务来说SQL Server仅仅能够识别外层的事务。嵌套事务是日志不正常增长的罪魁祸首之一因为开发人员以为回滚了内层事务,仅仅是回滚内层事务。

    但实际上当回滚内层事务时,会回滚整个内层事务,而不是仅仅是内层。这也是为什么我说嵌套事务并不存在。

    所以作为开发人员来讲,永远不要对事务进行嵌套。事务嵌套是邪恶的。

    如果你不相信我说的,那么通过下面的例子就就会相信。创建完数据库和表之后,每一条记录都会导致日志增加8K。

CREATE DATABASE NestedXactsAreNotReal; 
GO 
USE NestedXactsAreNotReal; 
GO 
ALTER DATABASE NestedXactsAreNotReal SET RECOVERY SIMPLE; 
GO 
CREATE TABLE t1 (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'a'); 
CREATE CLUSTERED INDEX t1c1 ON t1 (c1); 
GO 
SET NOCOUNT ON; 
GO

 

  测试 #1:回滚内部事务时仅仅回滚内部事务?

BEGIN TRAN OuterTran; 
GO

INSERT INTO t1 DEFAULT Values; 
GO 1000

BEGIN TRAN InnerTran; 
GO

INSERT INTO t1 DEFAULT Values; 
GO 1000

SELECT @@TRANCOUNT, COUNT (*) FROM t1; 
GO

 

    你可以看到得出的结果是2和2000,下面我来回滚内部的事务,按照我们的猜想应该只回滚1000条吧,但事实上你会得到如下结果:

ROLLBACK TRAN InnerTran; 
GO 

消息 6401,级别 16,状态 1,第 2 行 
无法回滚 InnerTran。找不到该名称的事务或保存点。

 

    好吧,由Books Online来看,我只能使用外部事务的名称或是将事务名称留空来进行回滚,代码如下:

ROLLBACK TRAN; 
GO

SELECT @@TRANCOUNT, COUNT (*) FROM t1; 
GO

 

    现在我得到结果是0和0。正如Books Online所言,这个回滚操作将外部事务进行了回滚并将全局变量@@TRANCOUNT设置为0。事务中所有的修改都被回滚,如果想部分回滚的话只能使用SAVE TRAN 和ROLLBACK TRAN。

   

测试 #2:嵌套事务中内部事务提交后会保存内部事务的修改吗?

BEGIN TRAN OuterTran; 
GO

BEGIN TRAN InnerTran; 
GO

INSERT INTO t1 DEFAULT Values; 
GO 1000

COMMIT TRAN InnerTran; 
GO

SELECT COUNT (*) FROM t1; 
GO

 

    正如我所期待,得到的结果是1000。这说明内部事务提交是会修改到磁盘的。但是如果这时外部事务回滚的话,那么不应该回滚内部事务…

ROLLBACK TRAN OuterTran; 
GO

SELECT COUNT (*) FROM t1; 
GO

 

    但运行上面查询后结果是0,这说明外部事务的回滚会影响内部事务。

 

测试 #3:提交嵌套的事务的内部事务至少可以让我清除日志吧。

   在开始这个测试之前我首先清除了日志,然后运行如下代码:

BEGIN TRAN OuterTran; 
GO

BEGIN TRAN InnerTran; 
GO

INSERT INTO t1 DEFAULT Values; 
GO 1000

DBCC SQLPERF ('LOGSPACE'); 
GO

   得到结果:

    2012-10-24_105050

  

    下面我将事务提交后运行CheckPoint(对于简单恢复模式的数据库将会截断日志),得到的结果:

COMMIT TRAN InnerTran; 
GO

CHECKPOINT; 
GO

DBCC SQLPERF ('LOGSPACE'); 
GO

 

    2

 

    我们发现日志的使用不减反赠,这是由于日志写入了CheckPoint记录(详情请看:How do checkpoints work and what gets logged)。提交内部事务不会导致日志被清除,这是由于外部事务回滚时也会连同内部事务一起回滚(译者注:所以这部分VLF在外部事务提交之前永远不会被标记位reusable)。所以这部分日志在外部事务提交之前永远不会被截断。为了证明这一点,我提交外部事务,然后再来看日志:

COMMIT TRAN OuterTran; 
GO

CHECKPOINT; 
GO

DBCC SQLPERF ('LOGSPACE'); 
GO

  3

 

    怎么样,日志使用百分比大幅下降了吧。

    对于嵌套事务来说---Just Say no。(这句话你可以当作来自SQLSkill.com的一个热心的家伙给的福利微笑)

分类: SQL Server DBA误区


本文转自CareySon博客园博客,原文链接:http://www.cnblogs.com/CareySon/archive/2013/01/22/2871204.html如需转载请自行联系原作者
相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
8天前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
2月前
|
SQL 运维 监控
SQL Server 运维常用sql语句(二)
SQL Server 运维常用sql语句(二)
25 3
|
2月前
|
SQL XML 运维
SQL Server 运维常用sql语句(三)
SQL Server 运维常用sql语句(三)
13 1
|
21天前
|
SQL 存储 监控
SQLServer事务复制延迟优化之并行(多线程)复制
【9月更文挑战第12天】在SQL Server中,事务复制延迟会影响数据同步性。并行复制可通过多线程处理优化这一问题,提高复制效率。主要优化方法包括:配置分发代理参数、优化网络带宽、调整系统资源、优化数据库设计及定期监控维护。合理实施这些措施可提升数据同步的及时性和可靠性。
|
1月前
|
SQL 安全 数据库
基于SQL Server事务日志的数据库恢复技术及实战代码详解
基于事务日志的数据库恢复技术是SQL Server中一个非常强大的功能,它能够帮助数据库管理员在数据丢失或损坏的情况下,有效地恢复数据。通过定期备份数据库和事务日志,并在需要时按照正确的步骤恢复,可以最大限度地减少数据丢失的风险。需要注意的是,恢复数据是一个需要谨慎操作的过程,建议在执行恢复操作之前,详细了解相关的操作步骤和注意事项,以确保数据的安全和完整。
59 0
|
2月前
|
SQL 监控 供应链
|
2月前
|
SQL 数据库 开发者
SQL中的子查询:嵌套查询的深度解析
【8月更文挑战第31天】
131 0
|
2月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
133 0
|
2月前
|
SQL 数据挖掘 数据库
SQL 子查询深度剖析来袭!嵌套查询竟有如此无限可能,带你轻松玩转复杂数据检索与操作!
【8月更文挑战第31天】在 SQL 中,子查询是一种强大的工具,允许在一个查询内嵌套另一个查询,从而实现复杂的数据检索和操作。子查询分为标量子查询、列子查询和行子查询,可用于 SELECT、FROM、WHERE 和 HAVING 子句中。例如,查找年龄大于平均年龄的学生或每个课程中成绩最高的学生。子查询具有灵活性、可重用性和潜在的性能优化优势,但需注意性能问题、可读性和数据库支持。合理使用子查询能够显著提升查询效率和代码维护性。
50 0
|
16天前
|
SQL 数据库
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例
SQL Server附加数据库出现错误823,附加数据库失败。数据库没有备份,无法通过备份恢复数据库。 SQL Server数据库出现823错误的可能原因有:数据库物理页面损坏、数据库物理页面校验值损坏导致无法识别该页面、断电或者文件系统问题导致页面丢失。
82 12
数据库数据恢复—SQL Server数据库报错“错误823”的数据恢复案例
下一篇
无影云桌面