在 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 | 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 | 60,000,000(六千萬) | 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) | 發行版數量 | 最大交易大小(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 | 60,000,000(六千萬) | 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 |
交易大小限制是依交易或操作套用。 此規定並非適用於所有同時進行的交易。 因此,每個交易都被允許將此量的資料寫入日誌。
為了優化並減少寫入日誌的資料量,請參考 《交易》最佳實務 條目。
警告
最大交易大小只能在資料分布均勻的 HASH 或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 區塊的錯誤資訊之前完成。
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。
下一步
欲了解更多交易優化,請參閱 交易最佳實務。 另外也提供 專用 SQL 池 與 無伺服器 SQL 池的最佳實務指南。