SQL Server 利用「使用者定義資料表類型」傳遞資料和加速

June 10, 2024

在 SQL Server 中,想要傳遞資料表給 SP,或是想將資料表放入記憶體加速,可以善用「使用者定義資料表類型」。

介紹

使用者定義資料表類型 (User-defined table type) 可以用來:

  1. 作為變數,傳遞一整組資料到預存程序 (Stored Procedure, SP)。
  2. 建立記憶體最佳化資料表 (Memory-optimized Table),增進查詢效率。使用記憶體來存放暫存資料時,不必再從磁碟建立 tempdb 資料庫中的暫存表,因此可以加快速度。(在建立表格時,使用 WITH ( MEMORY_OPTIMIZED = ON ) 關鍵字,且必須建立一組索引。) 

使用者定義資料表類型

範例  

1. CREATE TYPE 建立使用者定義資料表類型,同時需要建立索引,而且需加入 MEMORY_OPTIMIZED = ON  。

-- 建立「使用者定義資料表類型」
CREATE TYPE Person_MemOptimized AS TABLE
(Id INT PRIMARY KEY NONCLUSTERED 
 , [Name] VARCHAR(100)
) WITH ( MEMORY_OPTIMIZED = ON )

2. 建立 SP,此 SP 可以定義資料表類型的變數 (必須是唯讀,因此加入 READONLY  ),並接收資料。

-- 建立 SP
CREATE PROCEDURE Usp_InsertPersonMemOpt
@PersonData Person_MemOptimized READONLY
AS
-- SP 要執行的 SQL 語法
BEGIN
    SELECT Id, [Name] FROM @PersonData ;
END

3. 從查詢語法建立資料,並傳遞至 SP。

-- 宣告資料表類型變數
DECLARE @VarPerson_MemOptimized AS Person_MemOptimized 
 
-- 插入資料
INSERT INTO @VarPerson_MemOptimized 
VALUES (1, 'Alice')
INSERT INTO @VarPerson_MemOptimized 
VALUES (2, 'Bob')
INSERT INTO @VarPerson_MemOptimized 
VALUES (3, 'Candy')

-- 執行 SP
EXEC Usp_InsertPersonMemOpt @VarPerson_MemOptimized 

4. 用 DROP TYPE 卸除使用者定義資料表類型,如果有相依物件 (像 SP 或資料表) 的話,也要先 DROP 掉。

-- 參照的資料
DROP PROCEDURE [dbo].[SP_xxx]
GO

DROP TYPE [dbo].[Person_MemOptimized]
GO

初次使用

如果是第一次使用記憶體最佳化的相關功能,可能會遇到「資料庫的 MEMORY_OPTIMIZED_FILEGROUP 必須在線上」錯誤。此時需要執行以下指令,來建立資料庫的記憶體最佳化檔案群組和容器:

ALTER DATABASE AdventureWorks2019 ADD FILEGROUP AdventureWorks2019_mod CONTAINS MEMORY_OPTIMIZED_DATA -- 為已有的資料庫增加群組

ALTER DATABASE AdventureWorks2019 ADD FILE (name='AdventureWorks2019_mod1', filename='c:\data\AdventureWorks2019_mod1') TO FILEGROUP AdventureWorks2019_mod  -- 為群組增加容器 

以上的語法應該要將 AdventureWorks2019 字樣代換成實際使用的資料庫,以及想建立的檔案路徑。

留意

在兩個資料庫間建立相同結構的 User-Defined Table Type (UDT), 沒辦法用來傳遞資料 (例如做為 SP 的參數傳遞)。

例如下列情境:

  • DB_A 有一個 UDT:dbo.MyType
  • DB_B 也有一個 UDT:dbo.MyType(結構完全一樣)
  • 從 DB_A 呼叫 DB_B 的 SP,傳入該 UDT
EXEC DB_B.dbo.MyProc @MyParam = @MyTypeVar

會出現:

Operand type clash: MyType is incompatible with MyType

儘管結構相同,SQL Server 仍會視其為不同的型別。

請參考:sql server table type clash operand - Stack Overflow

參考資料

資料表值參數