有关在 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 字节
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 块中读取错误信息之前。
值得注意的是,专用 SQL 池不实现或支持 ERROR_LINE() 函数。 如果代码中有此函数,则需要将其删除,使其符合专用 SQL 池。 请改用代码中的查询标签来实现等效的功能。 有关详细信息,请参阅 LABEL 文章。
THROW 是用于在专用 SQL 池中引发异常的更现代的实现,但也支持 RAISERROR。 然而,有一些差异值得关注。
- 用户定义的错误消息编号不能位于 THROW 的 100,000 - 150,000 范围内
- RAISERROR 错误消息固定为 50,000
- 不支持 sys.messages
专用 SQL 池确实存在一些与事务相关的其他限制。 如下所示:
- 无分布式事务
- 不允许嵌套事务
- 禁止设置存档点
- 无已命名事务
- 没有已标记的交易
- 不支持在用户定义的事务中执行诸如 CREATE TABLE 之类的 DDL 操作
若要详细了解如何优化事务,请参阅 事务最佳做法。 还为 专用 SQL 池 和 无服务器 SQL 池提供了其他最佳做法指南。