AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 5233
Accepted
garik
garik
Asked: 2011-09-01 00:25:24 +0800 CST2011-09-01 00:25:24 +0800 CST 2011-09-01 00:25:24 +0800 CST

ROLLBACK 是快速操作吗?

  • 772

RDBMS 系统是否针对COMMIT操作进行了优化?操作的速度有多慢/快ROLLBACK,为什么?

sql-server-2008 performance
  • 5 5 个回答
  • 7493 Views

5 个回答

  • Voted
  1. Best Answer
    Mark Storey-Smith
    2011-09-01T01:02:56+08:002011-09-01T01:02:56+08:00

    对于 SQL Server,您可能会争辩说,提交操作只不过是将 LOP_COMMIT_XACT 写入日志文件并释放锁,这当然会比事务自 BEGIN TRAN 以来执行的每个操作的 ROLLBACK 更快。

    如果您正在考虑事务的每个操作,而不仅仅是提交,我仍然认为您的陈述不正确。排除外部因素,例如日志磁盘的速度与数据磁盘的速度相比,事务完成的任何工作的回滚都可能比首先完成​​的工作要快。

    回滚是读取更改的顺序文件并将它们应用到内存数据页。最初的“工作”必须生成执行计划、获取页面、连接行等。

    编辑:这取决于位...

    @JackDouglas 指出这篇文章描述了回滚可能比原始操作花费更长的时间的情况之一。该示例是一个 14 小时的事务,不可避免地使用并行性,这需要 48 多个小时才能回滚,因为回滚主要是单线程的。您很可能还会反复搅动缓冲池,因此您不再需要反转对内存页面的更改。

    所以,我之前的答案的修订版。回滚慢了多少?考虑到所有其他因素,对于典型的 OLTP 事务来说,情况并非如此。在典型范围之外,“撤消”可能比“做”花费更长的时间,但是(这是一个潜在的绕口令吗?)为什么将取决于“做”是如何完成的。

    Edit2:继评论中的讨论之后,这里有一个非常人为的例子来证明正在完成的工作是确定提交与回滚作为操作的相对成本的主要因素。

    创建两个表并低效地打包它们(每页浪费空间):

    SET STATISTICS IO OFF;
    SET STATISTICS TIME OFF;
    SET NOCOUNT ON;
    GO
    
    CREATE TABLE dbo.Foo
    (
        col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
        , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
    )
    
    CREATE TABLE dbo.Bar
    (
        col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
        , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
    )
    GO
    
    INSERT dbo.Foo DEFAULT VALUES
    GO 100000
    
    INSERT dbo.Bar DEFAULT VALUES
    GO 100000
    

    运行“错误”更新查询,测量完成工作所花费的时间和发出提交所花费的时间。

    DECLARE 
        @StartTime DATETIME2
        , @Rows INT
    
    SET @Rows = 1
    
    CHECKPOINT
    DBCC DROPCLEANBUFFERS
    
    BEGIN TRANSACTION
    
    SET @StartTime = SYSDATETIME()
    
    UPDATE
        dbo.bar
    SET
        col2 = REPLICATE('B', 4000)
    FROM
        dbo.bar b
    INNER JOIN
        (
        SELECT TOP(@Rows)
            col1
        FROM
            dbo.foo
        ORDER BY
            NEWID()
        ) f
    ON  f.col1 = b.col1
    OPTION (MAXDOP 1)
    
    SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())
    
    SET @StartTime = SYSDATETIME()
    
    COMMIT TRANSACTION
    
    SELECT 'Commit', DATEDIFF(ms, @StartTime, SYSDATETIME())
    GO
    

    再次执行相同操作,但发出并测量回滚。

        DECLARE 
        @StartTime DATETIME2
        , @Rows INT
    
    SET @Rows = 1
        
    CHECKPOINT
    DBCC DROPCLEANBUFFERS
    
    BEGIN TRANSACTION
    
    SET @StartTime = SYSDATETIME()
    
    UPDATE
        dbo.bar
    SET
        col2 = REPLICATE('B', 4000)
    FROM
        dbo.bar b
    INNER JOIN
        (
        SELECT TOP(@Rows)
            col1
        FROM
            dbo.foo
        ORDER BY
            NEWID()
        ) f
    ON  f.col1 = b.col1
    OPTION (MAXDOP 1)
    
    SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())
    
    SET @StartTime = SYSDATETIME()
    
    ROLLBACK TRANSACTION
    
    SELECT 'Rollback', DATEDIFF(ms, @StartTime, SYSDATETIME())
    GO
    

    使用 @Rows=1 我得到一个相当一致的结果:

    • 查找/更新需要 5500 毫秒
    • 3ms 提交
    • 1ms回滚

    使用@Rows=100:

    • 8500ms 查找/更新
    • 15 毫秒提交
    • 15ms 回滚

    使用@Rows=1000:

    • 15000ms 查找/更新
    • 10 毫秒提交
    • 500ms 回滚

    回到最初的问题。如果您要测量完成工作和提交所花费的时间,那么回滚就是胜出,因为大部分工作都用于查找要更新的行,而不是实际修改数据。如果您正在孤立地查看提交操作,那么应该清楚提交所做的“工作”很少。提交是“我完成了”。

    • 14
  2. Jack Douglas
    2011-09-01T00:36:59+08:002011-09-01T00:36:59+08:00

    对于 Oracle,回滚所花费的时间可能比进行回滚更改所花费的时间长很多倍。这通常无关紧要,因为

    1. 事务回滚时不持有任何锁
    2. 它由低优先级后台进程处理

    对于 SQL Server,我不确定情况是否相同,但其他人会说如果不是......

    至于“为什么”,我会说rollback应该是罕见的,通常只有在出现问题的情况下,当然commit可能更常见 - 所以优化是有意义的commit

    • 13
  3. Aaron Bertrand
    2011-09-01T05:27:27+08:002011-09-01T05:27:27+08:00

    回滚不仅仅是“哦,没关系”——在很多情况下,它确实必须撤消已经完成的操作。没有规定回滚操作总是比原始操作慢或总是快,尽管即使原始事务并行运行,回滚也是单线程的。如果您正在等待,我建议您继续等待是最安全的。

    当然,这一切都随着 SQL Server 2019 和Accelerated Database Recovery发生了变化(其代价也是可变的,允许即时回滚,而不管数据大小如何)。

    • 9
  4. StanleyJohns
    2011-09-01T05:17:33+08:002011-09-01T05:17:33+08:00

    并非所有事务的提交活动都会比回滚更好。一种这样的情况是 SQL 中的删除操作。当事务删除行时,这些行被标记为幽灵记录。一旦发出提交并且幽灵记录清理任务开始,那么只有这些记录被“删除”。

    如果改为发出回滚,它只会从这些记录中删除重影标记,而不是密集的插入语句。

    • 8
  5. Chris Travers
    2014-03-05T21:47:13+08:002014-03-05T21:47:13+08:00

    不是所有的都是。PostgreSQL 回滚不需要比提交更多的时间,因为这两个操作在磁盘 I/O 方面实际上是相同的。我实际上并不认为这是一个针对提交进行优化的问题,而是一个针对其他查询进行优化的问题。

    基本问题是如何处理磁盘布局以及这如何影响提交与回滚。回滚速度比提交慢的主要数据库倾向于将数据(尤其是来自聚集表的数据)移出主要数据结构,并在更新数据时将其放入回滚段中。这意味着要提交,您只需删除回滚段,但要回滚,您必须将所有数据复制回来。

    对于 PostgreSQL,所有表都是堆表,索引是独立的。这意味着在回滚或提交时,无需重新排列任何数据。这使得提交和回滚都很快。

    但是,它会使其他一些事情变慢一些。例如,主键查找必须遍历索引文件,然后必须命中堆表(假设没有适用的覆盖索引)。这没什么大不了的,但它确实添加了额外的页面查找,甚至可能添加了一些随机页面查找(如果该行发生了很多更新)以检查其他信息和可见性。

    然而,这里的速度不是 PostgreSQL 中写操作与读操作的优化问题。不愿意将某些读取操作的特权置于其他操作之上。因此 PostgreSQL 的平均性能与其他数据库一样好。只是某些操作可能更快或更慢。

    所以我认为实际的答案是数据库针对读取端的某些工作负载进行了优化,这导致了写入端的挑战。通常在有问题的地方,提交通常(尽管并非总是)会比回滚更受青睐。然而,这取决于执行任一操作的含义(更新与删除不同)。

    • 5

相关问题

  • 是否有开发人员遵循数据库更改的“最佳实践”类型流程?

  • 如何确定是否需要或需要索引

  • 从 SQL Server 2008 降级到 2005

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    您如何显示在 Oracle 数据库上执行的 SQL?

    • 2 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    我可以查看在 SQL Server 数据库上运行的历史查询吗?

    • 6 个回答
  • Marko Smith

    如何在 PostgreSQL 中使用 currval() 来获取最后插入的 id?

    • 10 个回答
  • Marko Smith

    如何在 Mac OS X 上运行 psql?

    • 11 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Marko Smith

    将数组参数传递给存储过程

    • 12 个回答
  • Martin Hope
    Manuel Leduc PostgreSQL 多列唯一约束和 NULL 值 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler 什么时候应该将主键声明为非聚集的? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    BrunoLM Guid vs INT - 哪个更好作为主键? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick 如何优化大型数据库的 mysqldump? 2011-01-04 13:13:48 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve