在 Azure Synapse Analytics 中使用专用 SQL 池处理事务

有关在 Azure Synapse Analytics 中使用专用 SQL 池实现事务以开发解决方案的提示。

可以预期什么

正如预期的那样,专用 SQL 池支持作为数据仓库工作负荷的一部分的事务。 但是,为了确保专用 SQL 库在规模上保持性能,与 SQL Server 相比某些功能是有限的。 本文重点介绍差异并列出其他差异。

事务隔离级别

专用 SQL 池实现 ACID 事务。 事务支持的隔离级别默认为 READ UNCOMMITTED。 在连接到 master 数据库时,可以通过打开用户数据库的 READ_COMMITTED_SNAPSHOT 数据库选项,将其更改为 READ COMMITTED SNAPSHOT ISOLATION。

启用后,此数据库中的所有事务都将在 READ COMMITTED SNAPSHOT ISOLATION 下执行,并且将不接受在会话级别设置 READ UNCOMMITTED。 有关详细信息,请查看 ALTER DATABASE SET 选项(Transact-SQL)。

交易规模

单个数据修改事务的大小有限。 此限制按分布应用。 因此,可以通过将限制乘以分布计数来计算总分配。

若要近似于事务中的最大行数,将分布上限除以每行的总大小。 对于可变长度列,请考虑采用平均列长度,而不是使用最大大小。

下表中已做出以下假设:

  • 出现平均数据分布
  • 平均行长度为 250 字节

Gen2

DWU 每个分布的上限 (GB) 分布的数量 最大事务大小 (GB) 每个分布的行数 每个事务的最大行数
DW100c 1 六十 六十 四百万 240,000,000
DW200c 1.5 六十 90 6,000,000 三亿六千万
DW300c 2.25 六十 135 9,000,000 540,000,000
DW400c 3 六十 180 12,000,000 720,000,000
DW500c 3.75 六十 225 1500万 900,000,000
DW1000c 7.5 六十 450 30,000,000 1,800,000,000
DW1500c 11.25 六十 675 45,000,000 2,700,000,000
DW2000c 15 六十 900 六千万 3,600,000,000
DW2500c 18.75 六十 1125 75,000,000 4,500,000,000
DW3000c 22.5 六十 1,350 90,000,000 5,400,000,000
DW5000c 37.5 六十 2,250 150,000,000 9,000,000,000
DW6000c 45 六十 2,700 180,000,000 10,800,000,000
DW7500c 56.25 六十 3,375 225,000,000 13,500,000,000
DW10000c 75 六十 4,500 300,000,000 18,000,000,000
DW15000c 112.5 六十 6,750 450,000,000 27,000,000,000
DW30000c 225 六十 13,500 900,000,000 54,000,000,000

第一代

DWU 每个分布的上限 (GB) 分布的数量 最大事务大小(GB) 每个分布的行数 每个事务的最大行数
DW100 1 六十 六十 400万 240,000,000
DW200 1.5 六十 90 6,000,000 三亿六千万
DW300 2.25 六十 135 9,000,000 540,000,000
DW400 3 六十 180 12,000,000 720,000,000
DW500 3.75 六十 225 一千五百万 900,000,000
DW600 4.5 六十 270 一千八百万 1,080,000,000
DW1000 7.5 六十 450 30,000,000 1,800,000,000
DW1200 9 六十 540 36,000,000 2,160,000,000
DW1500 11.25 六十 675 45,000,000 2,700,000,000
DW2000 15 六十 900 六千万 3,600,000,000
DW3000 22.5 六十 1,350 90,000,000 5,400,000,000
DW6000 45 六十 2,700 180,000,000 10,800,000,000

每个事务或操作都有事务大小限制。 它不会在所有并发事务中应用。 因此,允许每个事务将此数据量写入日志。

若要优化和最小化写入日志的数据量,请参阅 “事务最佳做法 ”一文。

警告

对于哈希或ROUND_ROBIN分布的数据表,只有当数据分布均匀时才能实现最大事务大小。 如果事务以倾斜的方式将数据写入分布区,则在最大事务大小之前可能会达到该限制。

事务状态

专用 SQL 池使用 XACT_STATE() 函数使用值 -2 报告失败的事务。 此值表示事务已失败并标记为仅可回滚。

备注

XACT_STATE函数中使用-2来表示失败的事务在SQL Server中表现出不同的行为。 SQL Server 使用值 -1 表示不可提交的事务。 SQL Server 可以容忍事务中的某些错误,而无需将其标记为不可提交。 例如,SELECT 1/0 会导致错误,但不会导致事务进入不可提交的状态。 SQL Server 还允许读取无法提交的事务。 但是,专用 SQL 池不允许执行此作。 如果在专用 SQL 池中的事务中发生错误,它将自动进入 -2 状态,并且在事务回滚之前无法执行任何进一步的 SELECT 语句。 因此,请务必检查应用程序代码是否使用 XACT_STATE(),因为可能需要进行代码修改。

例如,在 SQL Server 中,你可能会看到如下所示的事务:

SET NOCOUNT ON;
DECLARE @xact_state smallint = 0;

BEGIN TRAN
    BEGIN TRY
        DECLARE @i INT;
        SET     @i = CONVERT(INT,'ABC');
    END TRY
    BEGIN CATCH
        SET @xact_state = XACT_STATE();

        SELECT  ERROR_NUMBER()    AS ErrNumber
        ,       ERROR_SEVERITY()  AS ErrSeverity
        ,       ERROR_STATE()     AS ErrState
        ,       ERROR_PROCEDURE() AS ErrProcedure
        ,       ERROR_MESSAGE()   AS ErrMessage
        ;

        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRAN;
            PRINT 'ROLLBACK';
        END

    END CATCH;

IF @@TRANCOUNT >0
BEGIN
    PRINT 'COMMIT';
    COMMIT TRAN;
END

SELECT @xact_state AS TransactionState;

上述代码提供以下错误消息:

Msg 111233, Level 16, State 1, Line 1 111233;当前事务已中止,所有挂起的更改都已回退。 原因:仅回退状态的事务未在 DDL、DML 或 SELECT 语句之前显式回退。

无法获取 ERROR_* 函数的输出。

在专用 SQL 池中,代码需要略有更改:

SET NOCOUNT ON;
DECLARE @xact_state smallint = 0;

BEGIN TRAN
    BEGIN TRY
        DECLARE @i INT;
        SET     @i = CONVERT(INT,'ABC');
    END TRY
    BEGIN CATCH
        SET @xact_state = XACT_STATE();

        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRAN;
            PRINT 'ROLLBACK';
        END

        SELECT  ERROR_NUMBER()    AS ErrNumber
        ,       ERROR_SEVERITY()  AS ErrSeverity
        ,       ERROR_STATE()     AS ErrState
        ,       ERROR_PROCEDURE() AS ErrProcedure
        ,       ERROR_MESSAGE()   AS ErrMessage
        ;
    END CATCH;

IF @@TRANCOUNT >0
BEGIN
    PRINT 'COMMIT';
    COMMIT TRAN;
END

SELECT @xact_state AS TransactionState;

现在观察到了预期行为。 事务中的错误被管理,ERROR_* 函数按预期提供了值。

所做的一切改变是事务的 ROLLBACK 必须发生于在 CATCH 块中读取错误信息之前。

Error_Line() 函数

值得注意的是,专用 SQL 池不实现或支持 ERROR_LINE() 函数。 如果代码中有此函数,则需要将其删除,使其符合专用 SQL 池。 请改用代码中的查询标签来实现等效的功能。 有关详细信息,请参阅 LABEL 文章。

THROW 和 RAISERROR 的使用

THROW 是用于在专用 SQL 池中引发异常的更现代的实现,但也支持 RAISERROR。 然而,有一些差异值得关注。

  • 用户定义的错误消息编号不能位于 THROW 的 100,000 - 150,000 范围内
  • RAISERROR 错误消息固定为 50,000
  • 不支持 sys.messages

局限性

专用 SQL 池确实存在一些与事务相关的其他限制。 如下所示:

  • 无分布式事务
  • 不允许嵌套事务
  • 禁止设置存档点
  • 无已命名事务
  • 没有已标记的交易
  • 不支持在用户定义的事务中执行诸如 CREATE TABLE 之类的 DDL 操作

后续步骤

若要详细了解如何优化事务,请参阅 事务最佳做法。 还为 专用 SQL 池无服务器 SQL 池提供了其他最佳做法指南。