Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
本文包含有关在 SQL 池中实现事务和开发解决方案的提示。
可以预期什么
正如预期的那样,SQL 池支持作为数据仓库工作负荷的一部分的事务。 但是,为了确保大规模维护 SQL 池,与 SQL Server 相比,某些功能受到限制。 本文重点介绍差异。
事务隔离级别
SQL 数据池实现 ACID 事务。 事务支持的隔离级别默认为 READ UNCOMMITTED。 可以通过在连接到 master 数据库时,为用户 SQL 池启用 READ_COMMITTED_SNAPSHOT 数据库选项,将其更改为 READ COMMITTED SNAPSHOT 隔离级别。
启用后,此数据库中的所有事务都将在 READ COMMITTED SNAPSHOT ISOLATION 模式下执行,并且在会话级别设置的 READ UNCOMMITTED 将无效。 有关详细信息,请查看 ALTER DATABASE SET 选项(Transact-SQL)。
事务大小
单个数据修改事务的大小有限。 此限制按分布应用。 因此,可以通过将限制乘以分布计数来计算总分配。
若要近似于事务中的最大行数,将分布上限除以每行的总大小。 对于可变长度列,请考虑采用平均列长度,而不是使用最大大小。
下表中已做出两个假设:
- 数据已经均匀分布
- 平均行长度为 250 字节
Gen2
| DWU | 每个分布的上限(GB) | 分布数 | MAX 事务大小(GB) | 每个分布的行数 | 每个事务的最大行数 |
|---|---|---|---|---|---|
| DW100c | 1 | 60 | 60 | 4,000,000 | 240,000,000 |
| DW200c | 1.5 | 60 | 90 | 6,000,000 | 360,000,000 |
| DW300c | 2.25 | 60 | 135 | 9,000,000 | 540,000,000 |
| DW400c | 3 | 60 | 180 | 12,000,000 | 720,000,000 |
| DW500c | 3.75 | 60 | 225 | 15,000,000 | 900,000,000 |
| DW1000c | 7.5 | 60 | 450 | 30,000,000 | 1,800,000,000 |
| DW1500c | 11.25 | 60 | 675 | 45,000,000 | 2,700,000,000 |
| DW2000c | 15 | 60 | 900 | 六千万 | 3,600,000,000 |
| DW2500c | 18.75 | 60 | 1125 | 75,000,000 | 4,500,000,000 |
| DW3000c | 22.5 | 60 | 1,350 | 90,000,000 | 5,400,000,000 |
| DW5000c | 37.5 | 60 | 2,250 | 150,000,000 | 9,000,000,000 |
| DW6000c | 45 | 60 | 2,700 | 180,000,000 | 10,800,000,000 |
| DW7500c | 56.25 | 60 | 3,375 | 225,000,000 | 13,500,000,000 |
| DW10000c | 75 | 60 | 4,500 | 300,000,000 | 18,000,000,000 |
| DW15000c | 112.5 | 60 | 6,750 | 450,000,000 | 27,000,000,000 |
| DW30000c | 225 | 60 | 13,500 | 900,000,000 | 54,000,000,000 |
第一代
| DWU | 每个分布的上限(GB) | 分布数 | MAX 事务大小(GB) | 每个分布的行数 | 每个事务的最大行数 |
|---|---|---|---|---|---|
| DW100 | 1 | 60 | 60 | 4,000,000 | 240,000,000 |
| DW200 | 1.5 | 60 | 90 | 6,000,000 | 360,000,000 |
| DW300 | 2.25 | 60 | 135 | 9,000,000 | 540,000,000 |
| DW400 | 3 | 60 | 180 | 12,000,000 | 720,000,000 |
| DW500 | 3.75 | 60 | 225 | 15,000,000 | 900,000,000 |
| DW600 | 4.5 | 60 | 270 | 18,000,000 | 1,080,000,000 |
| DW1000 | 7.5 | 60 | 450 | 30,000,000 | 1,800,000,000 |
| DW1200 | 9 | 60 | 540 | 36,000,000 | 2,160,000,000 |
| DW1500 | 11.25 | 60 | 675 | 45,000,000 | 2,700,000,000 |
| DW2000 | 15 | 60 | 900 | 六千万 | 3,600,000,000 |
| DW3000 | 22.5 | 60 | 1,350 | 90,000,000 | 5,400,000,000 |
| DW6000 | 45 | 60 | 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,级别 16,状态 1,第 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_* 函数按预期返回值。
所有已更改的是,在读取 CATCH 块中的错误信息之前,事务的 ROLLBACK 必须发生。
Error_Line() 函数
值得注意的是,SQL 池不实现或支持 ERROR_LINE() 函数。 如果代码中有此内容,则需要将其删除,使其符合 SQL 池。
请改用代码中的查询标签来实现等效的功能。 有关详细信息,请参阅 LABEL 文章。
使用 THROW 和 RAISERROR
THROW 是用于在 SQL 池中引发异常的更现代的实现,但也支持 RAISERROR。 有一些差异值得注意。
- 用户定义的错误消息编号不能位于 THROW 的 100,000 - 150,000 范围内
- RAISERROR 错误消息固定为 50,000
- 不支持使用 sys.messages
局限性
SQL 池确实存在一些与事务相关的其他限制。
如下所示:
- 无分布式事务
- 不允许嵌套事务
- 不允许保存点
- 无命名事务
- 没有标记的交易
- 在用户定义的事务中不支持 DDL,例如 CREATE TABLE